MongoDB 拒绝使用索引交集
Posted
技术标签:
【中文标题】MongoDB 拒绝使用索引交集【英文标题】:MongoDB refuses to use index intersection 【发布时间】:2014-10-05 10:51:19 【问题描述】:我使用 MongoDB 2.6.4。
我的索引如下所示:
"v" : 1,
"key" :
"isFolder" : 1
,
"name" : "isFolder_1",
"ns" : "Tenant_51.files",
"background" : true
,
"v" : 1,
"key" :
"isForeign" : 1
,
"name" : "isForeign_1",
"ns" : "Tenant_51.files",
"background" : true
,
我的查询如下所示:
db.files.find( isFolder: true, isForeign: false ).explain(true)
由于某种原因,它选择仅使用 1 个索引(非常慢:680 秒!!)
看起来它确实计算了复杂计划,但是决定不使用它,我不明白为什么。 这是执行计划:
"cursor" : "BtreeCursor isFolder_1",
"isMultiKey" : false,
"n" : 107441,
"nscannedObjects" : 110580,
"nscanned" : 110580,
"nscannedObjectsAllPlans" : 110689,
"nscannedAllPlans" : 110801,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 21056,
"nChunkSkips" : 0,
"millis" : 679121,
"indexBounds" :
"isFolder" : [
[
true,
true
]
]
,
"allPlans" : [
"cursor" : "BtreeCursor isFolder_1",
"isMultiKey" : false,
"n" : 107441,
"nscannedObjects" : 110580,
"nscanned" : 110580,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" :
"isFolder" : [
[
true,
true
]
]
,
"cursor" : "BtreeCursor isForeign_1",
"isMultiKey" : false,
"n" : 68,
"nscannedObjects" : 109,
"nscanned" : 110,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" :
"isForeign" : [
[
false,
false
]
]
,
"cursor" : "Complex Plan",
"n" : 42,
"nscannedObjects" : 0,
"nscanned" : 111,
"nChunkSkips" : 0
],
"server" : "XXX",
"filterSet" : false,
"stats" :
"type" : "KEEP_MUTATIONS",
"works" : 128743,
"yields" : 21056,
"unyields" : 21056,
"invalidates" : 13834,
"advanced" : 107441,
"needTime" : 3140,
"needFetch" : 18161,
"isEOF" : 1,
"children" : [
"type" : "FETCH",
"works" : 128743,
"yields" : 21056,
"unyields" : 21056,
"invalidates" : 13834,
"advanced" : 107441,
"needTime" : 3140,
"needFetch" : 18161,
"isEOF" : 1,
"alreadyHasObj" : 0,
"forcedFetches" : 0,
"matchTested" : 107441,
"children" : [
"type" : "IXSCAN",
"works" : 110581,
"yields" : 21056,
"unyields" : 21056,
"invalidates" : 13834,
"advanced" : 110580,
"needTime" : 1,
"needFetch" : 0,
"isEOF" : 1,
"keyPattern" : " isFolder: 1 ",
"isMultiKey" : 0,
"boundsVerbose" : "field #0['isFolder']: [true, true]",
"yieldMovedCursor" : 0,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0,
"matchTested" : 0,
"keysExamined" : 110580,
"children" : [ ]
]
]
【问题讨论】:
您找到解决方案了吗?我在这里查看相同的问题(使用 MongoDB 3.2 和 3.4)。我无法弄清楚为什么它不做交叉路口,更糟糕的是,无论它依赖什么计划,它的性能都与 COLLSCAN 相同。实际上删除其中一个索引可以显着提高性能(但显然不是解决方案)。 不幸的是,答案是 MongoDB 的索引交集非常(非常)差,并且仅用于非常特定的场合。它更多的是营销而不是工程。不要指望它可以在任何实际用例中工作。只需使用单个索引。对不起。 谢谢,罗伊 :) 我得出了同样的结论。我的确切问题永远不会使用交集,因为它包含一个$exists
子句,显然它使它成为一个范围查询。但是即使去掉了那个子句,它仍然没有使用交集。我最终得到了很多单一的指数,以及一些复合指数,总的来说它仍然是一个巨大的改进。只需要忘记索引交集;)
【参考方案1】:
来自MongoDB docs about indexing:
MongoDB 只能使用一个索引来支持任何给定的操作。
然而,解决方案就像解释一样简单:使用复合索引。
db.files.ensureIndex(isFolder:1,isForeign:1)
【讨论】:
这只是文档中的一个错误。他们在 2.6 版中实现了索引交集。你可以看这里:docs.mongodb.org/manual/core/index-intersection 嗯,复合索引可以工作并且没有缺点。轮到你了。 它有缺点,它支持的查询选项较少。我无法为我想做的每个查询排列创建一个复合索引。这就是他们首先添加索引交集的原因。 问题中没有列出。我认为使用的计划在返回整个文件方面比复杂的计划更快。您可能需要使用相应的投影再次检查。 很简单,使用 isForeign 索引不会比 FETCH 阶段快。在这里困扰我的是,查询 100k 文档的 10 分钟是一种巨大的气味,尝试更好地为您的文档建模。以上是关于MongoDB 拒绝使用索引交集的主要内容,如果未能解决你的问题,请参考以下文章
mongodb AND查询遇到多个index时候可能会做交集——和复合索引不同