我试图理解为什么MongoDB无法使用here中提到的Index交集。
我已使用以下代码块在intersection
集合中插入了10000个文档:
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
for (var k = 0; k < 10; k++) {
for (var l = 0; l < 10; l++) {
db.intersection.insert({a:i, b:j, c:k, d:l});
}
}
}
}
然后创建了这3个索引:
db.intersection.createIndex({ a })
db.intersection.createIndex({ b : 1, c : 1 })
db.intersection.createIndex({ d : 1 })
此时我期待db.intersection.find({a:1,b:2,d:4})
使用3个索引之间的交集,即。 a_1, b_1_c_1, d_1
然而,事实并非如此,我可以看到获胜计划只使用一个索引,d_1
:
"winningPlan" : {
"stage" : "FETCH",
"filter" : {
"$and" : [
{
"a" : {
"$eq" : 1
}
},
{
"b" : {
"$eq" : 2
}
}
]
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"d" : 1
},
"indexName" : "d_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"d" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"d" : [
"[4.0, 4.0]"
]
}
}
},
抱歉,我无法发布allPlansExecution,因为它超出了正文字数限制
此外,db.inter.find({a:1,b:2})
的获胜计划也只使用一个索引b_1_c_1
。
有人可以为这些结果提供解释吗? 另外一个展示索引交叉点的实际例子会很有帮助。
答案 0 :(得分:1)
检查有关索引交叉的信息this jira ticket:
查询优化器可以选择索引交集计划 以下条件成立:
相关集合中的大多数文档都是磁盘驻留的。索引交集的优点是它可以避免获取 当交叉点的大小很小时完整的文档。如果 文件已经在记忆中,通过避免没有任何好处 提取
查询谓词是单点间隔,而不是范围谓词或一组间隔。单点间隔查询 返回按磁盘位置排序的文档,它允许优化器 选择计算非阻塞交叉点的计划 时尚。这通常比替代模式更快 计算交集,用于构建哈希表 从一个索引得到的结果,然后用结果来探测它 第二个指数。
- 要交叉的指数都不具有高度选择性。如果其中一个索引是选择性的,那么优化器将选择一个计划 它只是扫描这个选择性指数。
- 相对于单索引解决方案扫描的索引键数量,交集的大小较小。在这种情况下 查询执行程序可以使用索引查看较小的文档集 交叉,可能让我们获得更少的好处 从磁盘中提取。
醇>
显然,mongodb在大多数情况下可以做得更好而不使用索引,并且它选择拒绝交叉计划。很难想出一个确保mongodb将使用交叉点的例子。
对于您的示例,如果您看到以下查询的rejectedPlans:
onClick
你会发现这是其中一个计划(mongodb 3.4):
db.intersection.explain().find({a:1,b:2,d:4});
这个(AND_SORTED阶段)意味着mongodb确实将索引交叉视为一种可能性,但结论是d_1索引的表现要好得多。