您可以将 MongoDB 单字段索引视为一个数组,其中包含指向文档位置的指针。例如,如果您有一个集合(请注意,序列是故意乱序的):
[collection]
1: {a:3, b:2}
2: {a:1, b:2}
3: {a:2, b:1}
4: {a:1, b:1}
5: {a:2, b:2}
单字段索引
现在,如果你这样做:
db.collection.createIndex({a:1})
索引大致如下:
[index a:1]
1: {a:1} --> 2, 4
2: {a:2} --> 3, 5
3: {a:3} --> 1
注意三个重要的事情:
- 它是按
a
升序排列的
- 每个入口指向相关文档所在的位置
- 索引只记录
a
字段的值。该b
字段根本不存在于索引中
因此,如果您执行以下查询:
db.collection.find().sort({a:1})
它所要做的就是从上到下遍历索引,获取并输出条目指向的文档。请注意,您还可以从底部遍历索引,例如:
db.collection.find().sort({a:-1})
唯一的区别是您反向遍历索引。
因为b
根本不在索引中,所以在查询任何关于b
.
复合指数
在复合索引中,例如:
db.collection.createIndex({a:1, b:1})
这意味着您a
要先排序,然后再排序b
。索引看起来像:
[index a:1, b:1]
1: {a:1, b:1} --> 4
2: {a:1, b:2} --> 2
3: {a:2, b:1} --> 3
4: {a:2, b:2} --> 5
5: {a:3, b:2} --> 1
注意:
- 索引从
a
- 在每个里面
a
你都有一个排序的b
- 您有 5 个索引条目,而在前面的单字段示例中只有 3 个
使用此索引,您可以执行如下查询:
db.collection.find({a:2}).sort({b:1})
它可以很容易地找到a:2
然后将索引向前移动。鉴于该索引,您不能这样做:
db.collection.find().sort({b:1})
db.collection.find({b:1})
在这两个查询中,您都不容易找到b
,因为它遍布整个索引(即不在连续的条目中)。但是你可以这样做:
db.collection.find({a:2}).sort({b:-1})
因为您基本上可以找到它们的a:2
位置,然后将b
条目向后移动。
编辑:在评论中澄清@marcospgp 的问题:
{a:1, b:1}
如果您从排序表的角度来看,使用索引来满足的可能性find({a:2}).sort({b:-1})
实际上是有意义的。例如,索引{a:1, b:1}
可以被认为是:
a | b
--|--
1 | 1
1 | 2
2 | 1
2 | 2
2 | 3
3 | 1
3 | 2
查找({a:2}).sort({b:1})
该指数{a:1, b:1}
意味着sort by a, then within each a, sort the b values
。如果您然后执行 a find({a:2}).sort({b:1})
,则索引知道所有这些a=2
都在哪里。在这个块中a=2
,b
将按升序排序(根据索引规范),因此find({a:2}).sort({b:1})
可以通过以下方式满足查询:
a | b
--|--
1 | 1
1 | 2
2 | 1 <-- walk this block forward to satisfy
2 | 2 <-- find({a:2}).sort({b:1})
2 | 3 <--
3 | 1
3 | 2
查找({a:2}).sort({b:-1})
由于索引可以向前或向后走,因此遵循了类似的过程,最后有一个小扭曲:
a | b
--|--
1 | 1
1 | 2
2 | 1 <-- walk this block backward to satisfy
2 | 2 <-- find({a:2}).sort({b:-1})
2 | 3 <--
3 | 1
3 | 2
索引可以向前或向后走的事实是使查询find({a:2}).sort({b:-1})
能够使用索引的关键点{a:1, b:1}
。
查询规划器解释
您可以使用 . 查看查询计划程序的计划db.collection.explain().find(....)
。基本上,如果您看到stage
of COLLSCAN
,则表示没有使用索引或可用于查询。有关命令输出的详细信息,请参阅解释结果。