bottom line / tl;dr:如果查询和是否相等或不相等,b
则可以“跳过”索引,但例如,对于 sorts on ,则不能“跳过” 。a
c
c
这个问题问得好。不幸的是,我找不到任何可以更详细地权威地回答这个问题的东西。我相信此类查询的性能在过去几年中有所提高,因此我不会相信有关该主题的旧材料。
整个事情非常复杂,因为它取决于索引的选择性以及您是否查询相等、不等式和/或排序,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 }});
您的里程会有所不同。