【问题标题】:MongoDB Index intersection example?MongoDB索引交集示例?
【发布时间】:2017-09-11 12:16:04
【问题描述】:

我试图了解为什么 MongoDB 无法使用 here 中提到的索引交集。

我使用以下代码块在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}) 使用三个索引之间的交集,即。 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

有人可以解释一下这些结果吗? 演示索引交集的实际示例也会有所帮助。

【问题讨论】:

  • 确实是在使用索引交集。请参阅filter 查询计划的一部分。 ab 之间正在发生交集
  • 有两个阶段,第一个是输入阶段IXSCAN,它只使用d_1 索引,然后执行FETCH 阶段。这里没有涉及其他索引。

标签: mongodb indexing mongo-shell


【解决方案1】:

查看thisjira ticket 了解索引交叉点的信息:

查询优化器可以选择索引交集计划,当 以下条件成立:

  1. 相关集合中的大多数文档都驻留在磁盘上。索引交集的好处是可以避免抓取 当交叉点的大小很小时完成文档。如果 文档已经在内存中,避免没有任何好处 获取。

  2. 查询谓词是单点区间,而不是范围谓词或一组区间。单点区间查询 返回按磁盘位置排序的文档,这允许优化器 选择以非阻塞方式计算交叉点的计划 时尚。这通常比替代模式更快 计算交集,也就是建立一个哈希表 来自一个索引的结果,然后用来自 第二个索引。

  3. 两个要相交的索引都不是高度选择性的。如果其中一个索引是选择性的,那么优化器将选择一个计划 它只是扫描这个选择性索引。
  4. 相对于任一单索引解决方案扫描的索引键的数量,交集的大小很小。在这种情况下 查询执行器可以使用索引查看较小的文档集 交叉点,有可能让我们获得更少的收益 从磁盘获取。

显然,mongodb 在大多数情况下可以在不使用索引的情况下做得更好,它会选择拒绝交集计划。很难想出一个确保 mongodb 将使用交集的示例。

对于您的示例,如果您看到以下查询的被拒绝计划:

db.intersection.explain().find({a:1,b:2,d:4});

您会发现这是计划之一(mongodb 3.4):

{
    "stage" : "FETCH",
    "filter" : {
        "$and" : [
            {
                "d" : {
                    "$eq" : 4
                }
            },
            {
                "a" : {
                    "$eq" : 1
                }
            },
            {
                "b" : {
                    "$eq" : 2
                }
            }
        ]
    },
    "inputStage" : {
        "stage" : "AND_SORTED",
        "inputStages" : [
            {
                "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]"
                    ]
                }
            },
            {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "a" : 1
                },
                "indexName" : "a_1",
                "isMultiKey" : false,
                "multiKeyPaths" : {
                    "a" : [ ]
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "a" : [
                        "[1.0, 1.0]"
                    ]
                }
            }
        ]
    }
}

这个(AND_SORTED 阶段)意味着 mongodb 确实考虑了索引交叉的可能性,但得出的结论是 d_1 索引会执行得更好。

也看看这些答案:herehere

【讨论】:

  • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
  • @amod:根据您的评论改进了答案!
猜你喜欢
  • 2014-08-21
  • 2014-10-05
  • 1970-01-01
  • 1970-01-01
  • 2015-08-18
  • 1970-01-01
  • 2014-03-23
  • 2013-10-11
相关资源
最近更新 更多