Mongo三重复合指数

时间:2012-06-15 14:59:02

标签: mongodb mongodb-indexes

如果你有一个双复合索引{a:1,b:1},那么如果你单独查询 b 就不会使用索引是有意义的(即你不能在您的查询中“跳过” a )。但是,如果单独查询 a ,则会使用该索引。

但是,给定三重复合索引{a:1,b:1,c:1},我的explain命令显示在查询 a c时使用索引(即您可以在查询中“跳过” b )。

Mongo如何在 ac 的查询中使用 abc 索引,以及在这种情况下索引的效果如何?

背景

我的用例是有时我想查询a,b,c,有时我想查询a,c。现在我应该只在a,b,c上创建一个索引,还是应该在a,b上创建一个,b,c上创建一个?

(在a,c,b上创建索引没有意义,因为 c 是一个具有良好选择性的多键索引。)

2 个答案:

答案 0 :(得分:2)

底线/ tl; dr:如果ba查询是否存在相等或不平等,则可以“跳过”索引c,但不是,例如,对于c上的排序。

这是一个非常好的问题。不幸的是,我找不到任何权威性更详细地回答这个问题的内容。我相信这些查询的表现在过去几年有所改善,所以我不相信有关该主题的旧材料。

整个过程非常复杂,因为它取决于索引的选择性以及是否查询相等,不等和/或排序,所以explain()是你唯一的朋友,但这里有一些我发现的东西:

警告 :现在出现的是实验结果,推理和猜测的混合物。我可能会把Kyle的类比推得太远,而且我甚至可能完全错了(而且运气不好,因为我的测试结果与我的推理很相符)。

很明显,可以使用A的指数,这取决于A的选择性,当然非常有用。 '跳过'B可能很棘手,也可能不是。让我们保持这类似Kyle's cookbook example

French
    Beef
        ...
    Chicken
        Coq au Vin
        Roasted Chicken
    Lamb
        ...
    ...

如果您现在要我找一些名为“Chateaubriand”的法国菜,我可以使用索引A,因为我不知道该成分,所以必须扫描A中的所有菜肴。另一方面,我知道每个类别的菜肴列表都是通过索引C排序的,所以我只需要在每个成分列表中查找以“Cha”开头的字符串。如果有50种成分,我将需要50次查找,而不只是一次,但这比扫描每道法国菜要好得多!

  

在我的实验中,这个数字远远小于b中不同值的数量:它似乎永远不会超过2.但是,我只用一个集合来测试它,它可能需要做具有b - 索引的选择性。

如果你让我给你一个按字母顺序排列的所有法国菜肴列表,我会遇到麻烦。现在C上的索引毫无价值,我必须合并排序所有这些索引列表。我必须扫描每个元素才能这样做。

这反映在我的测试中。这是一些简化的结果。原始集合有日期时间,整数和字符串,但我想保持简单,所以它现在都是整数。

基本上,只有两类查询:nscanned< = 2 * limit,以及必须扫描整个集合的查询(120k文档)。索引是{a, b, c}

// fast (range query on c while skipping b)
> db.Test.find({"a" : 43, "c" : { $lte : 45454 }});
// slow (sorting)
> db.Test.find({"a" : 43, "c" : { $lte : 45454 }}).sort({ "c" : -1});
> db.Test.find({"a" : 43, "c" : { $lte : 45454 }}).sort({ "b" : -1}); 

// fast (can sort on c if b included in the query)
> db.Test.find({"a" : 43, "b" : 7887, "c" : { $lte : 45454 }}).sort({ "c" : -1});

// fast (older tutorials claim this is slow)
> db.Test.find({"a" : {$gte : 43}, "c" : { $lte : 45454 }});

您的里程会有所不同。

答案 1 :(得分:1)

您可以查看A和C上的查询作为查询A的特殊情况(在这种情况下将使用索引)。使用索引比必须加载整个文档更有效。

假设您希望获得A的所有文档在7到13之间,C在5到8之间。

如果您的A上只有索引:数据库可以使用索引选择A在7到13之间的文档,但为了确保C介于5和8之间,它也必须检索相应的文档。

如果你有A,B和C的索引:数据库可以使用索引来选择A在7和13之间的文档。由于C的值已经存储在索引的记录中,它可以确定相应的文件是否也符合C标准,而不必检索这些文件。因此,您可以避免磁盘读取,并获得更好的性能。