为啥这个覆盖查询的 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
字段仍然是错误的。我也尝试过使用提示显式提供索引,但没有改变。在这种情况下,nscannedObjectsAllPlans
和 nscannedAllPlans
的值为 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 属性为假的主要内容,如果未能解决你的问题,请参考以下文章