一个mongodb 查询问题2024.08.08

问题的引出:有个需求是删除N久之前的数据,但是数据结构如下。是要按照sendtime来进行判断的,还要UID符合一定的规则。其中UID是有索引。

type MsgInfo struct {
    SendTime    int64
    ClientMsgID string
    Msg         []byte
}

type UserChat struct {
    UID string
    Msg []MsgInfo
}

我一开始采用的是按照UID模糊查询,然后查找时间小于sendTime来计算。代码如下

findOpts := options.Find().SetLimit(perPage).SetSkip(page * perPage).SetSort(bson.M{"uid": 1})
cursor, err := c.Find(ctx, bson.M{"uid": bson.M{"$regex": regex}, "msg.sendtime": bson.M{"$lte": expireTime}}, findOpts)

结果发现查询的速度很慢。 一开始以为是sendtime没建索引的问题。结果创建了索引也没用,并且连索引都不会命中。
去除msg.sendtime条件后,发现速度还是很慢,那只能模糊匹配的问题,应该是大数据量的字符串匹配有问题。
然后尝试只用msg.sendtime条件,确实可以查出结果,但是速度不高,且不会使用索引。所以这两条路都不符合要求。
在最终发现mongo的document里_id的值,objectID的生成方法。

ObjectID由12个字节组成,其中:

4个字节是 Unix 时间戳(精确到秒,而不是毫秒)。
3个字节是客户端机器的唯一标识符,一般是机器的 MAC 地址。
2个字节是由进程 PID(进程标识符)生成的随机数。
3个字节由随机数生成。
ObjectID的格式十六进制字符串,例如:“507f1f77bcf86cd799439012”。

这个document创建的时候自动生成的,可以直接当作创建时间来看。 这样我可以只需要找到N久之前的文档,然后再用UID去模糊匹配一下量就小很多了。查找文档后发现可以直接用lte,gte直接来比较objectID。

1723105714726.png

所以这条路应该可行的,并且可以限制时间范围,进行循环多次查询,还可以达到减轻mongodb压力,避免影响主业务的目的。最初的开始时间可以直接查最早的一条。

startObjID := primitive.NewObjectIDFromTimestamp(time.Unix(startTick, 0))
endObjID := primitive.NewObjectIDFromTimestamp(time.Unix(endTick, 0))
findOpts := options.Find().SetLimit(perPage).SetSkip(page * perPage).SetSort(bson.M{"uid": 1})
cursor, err := c.Find(ctx, bson.M{"_id": bson.M{"$lte": endObjID, "$gte": startObjID}, "uid": bson.M{"$regex": regex}}, findOpts)

查最早的那条的方法

var result bson.M
findOneOpts := options.FindOne().SetSort(bson.M{"_id": 1})
if err := c.FindOne(ctx, bson.M{"_id": bson.M{"$lte": objID}, "uid": bson.M{"$regex": regex}}, findOneOpts).Decode(&result); err != nil {
    zlog.ZError("find one err", err, operationID, appID, "objectID", objID)
    return
}
//result["_id"].(primitive.ObjectID)
if result == nil {
    return
}
value, ok := result["_id"]
if !ok {
    return
}
startTick := value.(primitive.ObjectID).Timestamp().Unix() //一个月

最终测试了一下之后,果然速度很快,大大的提高了效率,符合要求

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容