当 INDEX 匹配时,MongoDB 阶段是不是应该避免 FETCH?
Posted
技术标签:
【中文标题】当 INDEX 匹配时,MongoDB 阶段是不是应该避免 FETCH?【英文标题】:Does MongoDB stages should avoid FETCH when INDEX is matching?当 INDEX 匹配时,MongoDB 阶段是否应该避免 FETCH? 【发布时间】:2020-02-21 04:38:47 【问题描述】:根据文档,当索引覆盖查询时,MongoDB 应该跳过 FETCH 阶段。
如果我理解正确,这句话解释了这种行为:
覆盖查询当索引覆盖查询时,MongoDB 可以同时匹配 查询条件并仅使用索引键返回结果; 即 MongoDB 不需要检查集合中的文档以 返回结果。
当索引覆盖查询时,解释结果有一个 IXSCAN 阶段 这不是 FETCH 阶段的后代,并且在 executionStats 中, totalDocsExamined 为 0。
在早期版本的 MongoDB 中,cursor.explain() 返回 indexOnly 字段指示索引是否覆盖查询。 (https://docs.mongodb.com/manual/reference/explain-results/)
还有这个
有了这个,查询花费不到 2 毫秒。因为索引 “覆盖”查询,MongoDB 能够匹配查询条件 并仅使用索引键返回结果;甚至不需要 检查集合中的文档以返回结果。 (如果 您会在 执行计划然后索引“覆盖”了查询。)(https://studio3t.com/knowledge-base/articles/mongodb-index-strategy/)
但在测试场景中它不会发生:
测试示例:
db.Test.insert("Field1":"data on field1: 1","Field2":"data on field2: 1");
db.Test.insert("Field1":"data on field1: 2","Field2":"data on field2: 2");
db.Test.insert("Field1":"data on field1: 3","Field2":"data on field2: 3");
db.Test.insert("Field1":"data on field1: 4","Field2":"data on field2: 4");
db.Test.insert("Field1":"data on field1: 5","Field2":"data on field2: 5");
db.Test.insert("Field1":"data on field1: 6","Field2":"data on field2: 6");
在我为 Field2 创建索引之后。
db.Test.createIndex("Field2":1)
然后我查询集合:
db.Test.find("Field2":"data on field2: 5").explain("executionStats");
我期待一个不是FETCH
阶段的子阶段IDXSCAN
。但是输出是这样的:
[...]
"winningPlan" :
"stage" : "FETCH",
"inputStage" :
"stage" : "IXSCAN",
"keyPattern" :
"Campo2" : 1.0
,
"indexName" : "Field2_1",
"isMultiKey" : false,
"multiKeyPaths" :
"Campo2" : []
,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" :
"Field2" : [
"[\"data on field2: 5", \"data on field2: 5\"]"
]
,
[...]
有两个阶段:一个 "stage" : "FETCH", 及其子 "stage" : "IXSCAN",。
谁能解释我的误解?
*** 关于投影
使用投影运行查询时
"winningPlan" :
"stage" : "PROJECTION",
"transformBy" :
"Campo2" : 1.0
,
"inputStage" :
"stage" : "FETCH",
"inputStage" :
"stage" : "IXSCAN",
"keyPattern" :
"Field2" : 1.0
,
"indexName" : "Field2_1",
"isMultiKey" : false,
"multiKeyPaths" :
"Campo2" : []
,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" :
"Field2" : [
"[\"data on field2: 5", \"data on field2: 5\"]"
]
,
亚当的回答是:成功了!
我意识到投影不应包含“_id”以避免FETCH
。
【问题讨论】:
【参考方案1】:您的查询没有指定projection,这意味着它将返回文档中的所有字段。这意味着 Field2: 1
索引不包含查询,因为它只包含一个字段。
以下查询应该被完全覆盖并且不应该有一个 FETCH 阶段。请注意,投影明确排除了_id
字段,如will be included in the projection unless specified otherwise:
db.Test.find(
"Field2":"data on field2: 5",
"Field2" : 1, "_id" : 0
).explain("executionStats");
输出:
"queryPlanner" :
"plannerVersion" : 1,
"namespace" : "foo.Test",
"indexFilterSet" : false,
"parsedQuery" :
"Field2" :
"$eq" : "data on field2: 5"
,
"winningPlan" :
"stage" : "PROJECTION",
"transformBy" :
"Field2" : 1,
"_id" : 0
,
"inputStage" :
"stage" : "IXSCAN",
"keyPattern" :
"Field2" : 1
,
"indexName" : "Field2_1",
"isMultiKey" : false,
"multiKeyPaths" :
"Field2" : [ ]
,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" :
"Field2" : [
"[\"data on field2: 5\", \"data on field2: 5\"]"
]
,
"rejectedPlans" : [ ]
,
"executionStats" :
"executionSuccess" : true,
"nReturned" : 1,
"executionTimeMillis" : 1,
"totalKeysExamined" : 1,
"totalDocsExamined" : 0,
"executionStages" :
"stage" : "PROJECTION",
"nReturned" : 1,
"executionTimeMillisEstimate" : 0,
"works" : 2,
"advanced" : 1,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"transformBy" :
"Field2" : 1,
"_id" : 0
,
"inputStage" :
"stage" : "IXSCAN",
"nReturned" : 1,
"executionTimeMillisEstimate" : 0,
"works" : 2,
"advanced" : 1,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" :
"Field2" : 1
,
"indexName" : "Field2_1",
"isMultiKey" : false,
"multiKeyPaths" :
"Field2" : [ ]
,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" :
"Field2" : [
"[\"data on field2: 5\", \"data on field2: 5\"]"
]
,
"keysExamined" : 1,
"seeks" : 1,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
,
"serverInfo" :
...
,
"ok" : 1,
...
【讨论】:
我是这么想的,但不是。查询有投影时的输出: "stage" : "PROJECTION", ... "stage" : "FETCH", // [NOT CHILD] "stage" : "IXSCAN", // [CHILD] 你在使用排序规则吗? @Rafael,您是否使用 Adam 提供的“executionStats”运行了相同的查询? 谢谢...它起作用了我意识到投影不应包含“_id”以避免 FETCH。 现在清楚了……索引没有“_id”,那就不会被覆盖了。以上是关于当 INDEX 匹配时,MongoDB 阶段是不是应该避免 FETCH?的主要内容,如果未能解决你的问题,请参考以下文章
在 go mongodb 中的 From Table 上匹配阶段
MongoDB 聚合中的多个 $project 阶段是不是会影响性能
为啥在与数组中的字段匹配时,mongoDB聚合中的查找中的管道不起作用?