如何消除 MongoDB 中的查询目标:已扫描对象/返回数已超过 1000?

zan*_*ngw 6 indexing mongodb mongodb-atlas

有一些问题1、2谈论MongoDB警告,但是,我的问题是另一种情况Query Targeting: Scanned Objects / Returned has gone above 1000

我们文档的架构是

{
    "_id" : ObjectId("abc"),
    "key" : "key_1",
    "val" : "1",
    "created_at" : ISODate("2021-09-25T07:38:04.985Z"),
    "a_has_sent" : false,
    "b_has_sent" : false,
    "updated_at" : ISODate("2021-09-25T07:38:04.985Z")
}
Run Code Online (Sandbox Code Playgroud)

该集合的索引是

{
    "key" : {
        "updated_at" : 1
    },
    "name" : "updated_at_1",
    "expireAfterSeconds" : 5184000,
    "background" : true
},
{
    "key" : {
        "updated_at" : 1,
        "a_has_sent" : 1,
        "b_has_sent" : 1
    },
    "name" : "updated_at_1_a_has_sent_1_b_has_sent_1",
    "background" : true
}

Run Code Online (Sandbox Code Playgroud)

之后的文档总数2021-09-24超过600000,并且distinct值为key5。

上面的衰弱是由查询引起的 db.collectionname.find({ "updated_at": { "$gte": ISODate("2021-09-24")}, "$or": [{ "a_has_sent": false }, {"b_has_sent": false}], "key": "key_1"})

我们的服务器同时发送一个文档到ab,批量大小为2000。发送到a成功后,标记a_has_senttrue。同样的逻辑b。随着发送过程的继续,文档的数量会a_has_sent: false减少。并且出现上述警告。

检查explain此查询的结果后,使用名为的索引updated_at_1而不是updated_at_1_a_has_sent_1_b_has_sent_1

我们尝试过的。

  1. 我们添加另一个新索引{"updated_at": 1, "key": 1},并期望该查询可以使用新索引来减少扫描文档的数量。不幸的是,我们失败了。updated_at_1仍使用指定的索引。
  2. 我们尝试替换findaggregate aggregate([{"$match": { "updated_at": { "$gte": ISODate("2021-09-24") }, "$or": [{ "a_has_sent": false }, { "b_has_sent": false}], "key": "key_1"}}]). 不幸的是,指定的索引updated_at_1仍然被使用。

我们想知道如何消除这个警告Scanned Objects / Returned has gone above 1000

我们的案例使用的是 Mongo 4.0。

Joe*_*Joe 3

MongoDB 无法使用单个索引来处理$or查看不同字段值的索引。

索引于

{
        "updated_at" : 1,
        "a_has_sent" : 1,
        "b_has_sent" : 1
}
Run Code Online (Sandbox Code Playgroud)

可以与 $or 表达式一起使用来匹配a_has_sentor b_has_sent

为了最大限度地减少检查的文档数量,请创建 2 个索引,每个索引对应 $or 的每个分支,并与封闭的 $and 组合(过滤器隐式地将顶级查询谓词与 and 组合起来)。例如:

{
        "updated_at" : 1,
        "a_has_sent" : 1
}
Run Code Online (Sandbox Code Playgroud)

{
        "updated_at" : 1,
        "b_has_sent" : 1
}
Run Code Online (Sandbox Code Playgroud)

另请注意,警报Query Targeting: Scanned Objects / Returned has gone above 1000并不涉及单个查询。

MongoDB 服务器保留一个计数器(64 位?),用于跟踪自服务器启动以来检查的文档数量,另一个计数器用于记录返回的文档数量。

通过简单地将检查的计数器除以返回的计数器来得出每个返回的定量扫描的结果。

这意味着,如果您有类似count需要检查文档的查询之类的内容,则可能检查了数百或数千个文档,但只返回了 1 个。不需要很多此类查询就能使比率超过 1000 个警报限制