为啥这个覆盖查询的 indexOnly 属性为假

Posted

技术标签:

【中文标题】为啥这个覆盖查询的 indexOnly 属性为假【英文标题】:Why indexOnly attribute is false for this covered query为什么这个覆盖查询的 indexOnly 属性为假 【发布时间】:2014-09-03 05:16:13 【问题描述】:

我有一个包含字段 _id、姓名、年龄、日期的测试数据库

索引:

[
    
            "v" : 1,
            "key" : 
                    "_id" : 1
            ,
            "name" : "_id_",
            "ns" : "blogger.users"
    ,
    
            "v" : 1,
            "key" : 
                    "name" : 1,
                    "age" : 1
            ,
            "name" : "name_1_age_1",
            "ns" : "blogger.users"
    ,
    
            "v" : 1,
            "key" : 
                    "age" : 1,
                    "name" : 1
            ,
            "name" : "age_1_name_1",
            "ns" : "blogger.users"
    
]

运行以下查询时:

> db.users.find("name":"user10","_id":0,"date":0)
     .explain()

我得到以下信息:


    "cursor" : "BtreeCursor name_1_age_1",
    "isMultiKey" : false,
    "n" : 1,
    "nscannedObjects" : 1,
    "nscanned" : 1,
    "nscannedObjectsAllPlans" : 2,
    "nscannedAllPlans" : 2,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 0,
    "indexBounds" : 
            "name" : [
                    [
                            "user10",
                            "user10"
                    ]
            ],
            "age" : [
                    [
                            
                                    "$minElement" : 1
                            ,
                            
                                    "$maxElement" : 1
                            
                    ]
            ]
    ,
    "server" : "Johny-PC:27017",
    "filterSet" : false

不解释结果是:

 "name" : "user10", "age" : 68 

即使这是一个具有正确预测的覆盖查询,indexOnly 字段仍然是错误的。我也尝试过使用提示显式提供索引,但没有改变。在这种情况下,nscannedObjectsAllPlansnscannedAllPlans 的值为 1,因为查询不会尝试其他索引。

【问题讨论】:

【参考方案1】:

对于要“indexOnly”或“covered”的查询,返回的唯一字段必须包含在索引中。因此,即使您有“name_1_age_1”的索引,查询引擎仍然希望“告知”您想要的唯一字段是索引中的字段。在您检查文档之前,它不知道该文档的相关信息:

db.users.find("name":"user10","_id":0, "name": 1, "age": 1 ).explain()

这将返回“indexOnly”,因为查询引擎知道所选索引包含输出所需的所有字段。因此,如果有其他字段要返回,则无需返回集合。

【讨论】:

另外,我添加了 _id:0 的投影。我想这就够了吗? @johny 不,不会。您始终可以“排除”_id,但您不能混合和匹配其他字段。这意味着您可以明确地包含或排除。不是都。所以_id是这里唯一的例外 现实情况是我实际上从问题中排除了一个字段(日期),我认为这无关紧要。因此,如果我也必须排除该键,则会出现此错误。 @johny 答案解释说仅仅排除_id 还不够清楚。 MongoDB 是无模式的。查询优化器不可能告诉所有文档只包含所选索引中的字段。这就是为什么你告诉它你想要哪些字段。 _id 不存在于索引中,因此您排除它并仅包含存在的字段。老实说,如果您只是运行该语句,对您来说会简单得多。

以上是关于为啥这个覆盖查询的 indexOnly 属性为假的主要内容,如果未能解决你的问题,请参考以下文章

为啥即使条件为假,这个“IF”也总是执行?

为啥 C# 中的 1 && 2 为假?

"error": "索引未定义,添加 ".indexOn"

Firebase 安全规则:.indexOn 唯一 ID

我被嘲笑了:被查询的列,为啥要放到索引里?(1分钟系列)

我被嘲笑了:被查询的列,为啥要放到索引里?(1分钟系列)