3

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

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

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

背景:

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

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

4

2 回答 2

3

bottom line / tl;dr:如果查询和是否相等或不相等,b则可以“跳过”索引,但例如,对于 sorts on ,则不能“跳过” 。acc

这个问题问得好。不幸的是,我找不到任何可以更详细地权威地回答这个问题的东西。我相信此类查询的性能在过去几年中有所提高,因此我不会相信有关该主题的旧材料。

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

警告:现在出现的是实验结果、推理和猜测的混合体。我可能把凯尔的类比延伸得太远了,我什至可能完全错了(而且很不幸,因为我的测试结果与我的推理松散地吻合)。

显然可以使用 A 的索引,这取决于 A 的选择性,当然很有帮助。“跳过” B 可能很棘手,也可能没有。让我们保持类似于Kyle 的食谱示例

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

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

在我的实验中,这个数字比 中的不同值的数量要小得多b:它似乎从未超过 2。但是,我只用一个集合进行了测试,这可能与b-index 的选择性有关。

不过,如果你要我给你一份按字母顺序排列的所有法国菜的清单,那我就麻烦了。现在上的索引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 }});

您的里程会有所不同。

于 2012-06-19T00:05:58.267 回答
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 标准,而无需检索这些文档。因此,您将避免磁盘读取,从而获得更好的性能。

于 2012-06-15T15:03:51.410 回答