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时候可能会做交集——和复合索引不同

MongoDB Indexes

MongoDB:如何确定 GeoJson LineString 和具有半径的点的交集

window7拒绝连接MongoDB怎么办?

mongodb无法启动,由于目标计算机积极拒绝,无法连接

Docker,Mongodb,Windows 上的 Spring Boot 出现连接被拒绝错误