你可以将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
- 相比之前单字段示例中的3个索引条目,您现在有5个索引条目
使用此索引,您可以进行以下查询:
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
find({a:2}).sort({b:1})
索引 {a:1, b:1}
表示 按照 a 排序,然后在每个 a 中,对 b 值进行排序
。如果你执行 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
find({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
为COLLSCAN
,则该查询未使用索引或无法使用索引。有关命令输出的详细信息,请参见explain results。
db.posts.find({user_id: 1}).order({slug: -1})
(https://docs.mongodb.com/manual/tutorial/sort-results-with-indexes/#sort-on-multiple-fields)。对于相等性查询,索引方向并不重要。 - Sergio Tulentsev