如果我们有这样的收藏
{ a:1, b:1, c:1 }
{ a:1, b:1, c:2 }
{ a:1, b:1, c:3 }
{ a:1, b:2, c:1 }
... // all permutations up to:
{ a:3, b:3, c:3 }
以随机顺序想象这个集合
这就是 ({a:1,b:1,c:1}) 上的复合索引的样子
a: | 1 | 2 | 3 |
|-----------------+-----------------+-----------------|
b: | 1 | 2 | 3 | 1 | 2 | 3 | 1 | 2 | 3 |
|-----+-----+-----+-----+-----+-----+-----+-----+-----|
c: |1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|
对于每个 a,您依次拥有所有 b 和所有 c,好吗?
对于查询:db.xx.find({a:2}).sort({b:1}),您可以看到 b 元素在 a=2; 下方按顺序排列。索引将用于排序 - “scanAndOrder”: explain() 中的 false。如果您的查询是db.xx.find({a:2,c:{$in:[1,3]}}).sort({b:1}) ,也会发生同样的情况
但是这个:db.xx.find({a:{$in:[1,3]}}).sort({b:1}).explain()会告诉你"scanAndOrder" : true,这意味着index 不用于排序(尽管它用于查询) - 从上面的模式中您可以看到,“b”不是 a=[1,3] 的顺序。
这就是为什么索引的有效顺序是:
(1) exact matches (only one!)
(2) sort criteria
(3) matches that point to more than one document
在您的情况下,没有完全匹配;两个查询都返回多个文档。让我们在我们的示例中尝试一下:
db.xx.find({a:{$in:[1,3]},b:{$in:[1,3]}}).sort({c:1}).explain():使用index 用于查询,但不用于排序,它扫描 15 并返回 12 个对象。
db.xx.find({b:{$in:[1,3]},c:{$in:[1,3]}}).sort({a:1}).explain():使用用于查询和排序的索引,但扫描 21 并返回 12 个对象。
哪一个更好?这将取决于您的用例。如果您的查找通常返回许多文档,那么让排序使用索引可能会更有效 - 但如果它通常只返回几个(在许多中),那么您可能更喜欢更有效的扫描。尝试一下,看看使用 explain() 有什么更好的
这有帮助吗?
问候
罗纳德
PS我用它来创建示例集合:
[1,2,3].forEach(function(a){
[1,2,3].forEach(function(b){
[1,2,3].forEach(function(c){
db.xx.insert({a:a,b:b,c:c});
})
})
})