在MongoDB中,排序操作可以通过基于索引中的顺序检索文档来获得排序顺序。如果查询计划者无法从索引中获得排序顺序,它将对内存中的结果进行排序。与不使用索引的排序操作相比,使用索引的排序操作通常具有更好的性能。此外,不使用索引的排序操作在使用32 MB内存时将中止。
注意
由于MongoDB 3.6中对数组字段的排序行为发生了变化,因此在对使用多键索引建立索引的数组上进行排序时 ,查询计划包括一个阻塞的SORT阶段。新的排序行为可能会对性能产生负面影响。
在阻塞式SORT中,必须在排序步骤中使用所有输入,然后才能产生输出。在非阻塞或索引排序中,排序步骤扫描索引以按请求的顺序产生结果。
如果在单个字段上是升序还是降序索引,则对该字段的排序操作可以是任意方向。
例如,在a
集合的字段上创建一个升序索引records
:
该索引可以支持对的升序排序a
:
a
通过以相反的顺序遍历索引,索引还可以支持以下降序排序:
创建复合索引以支持对多个字段进行排序。
您可以在索引的所有键或子集上指定排序。但是,排序键必须按照它们在索引中出现的顺序列出。例如,索引键模式可以支持on 而不是 on 的排序。{ a: 1, b: 1
}
{ a: 1, b: 1 }
{ b: 1, a:
1 }
为了使查询使用复合索引进行排序,cursor.sort()
文档中所有键的指定排序方向必须与索引键模式匹配或与索引键模式的倒数匹配。例如,一个索引键图案可以支持对一类和,但不是
上或。{ a: 1, b: -1 }
{ a: 1, b: -1 }
{ a: -1, b: 1 }
{ a: -1, b: -1 }
{a: 1, b: 1}
如果排序键对应于索引键或索引前缀,则MongoDB可以使用索引对查询结果进行排序。甲前缀的化合物指数的是,在索引关键字模式的开始包括一个或多个键的子集。
例如,在data
集合上创建一个复合索引:
然后,以下是该索引的前缀:
以下查询和排序操作使用索引前缀对结果进行排序。这些操作不需要对内存中的结果集进行排序。
例 | 索引前缀 |
---|---|
db.data.find().sort( { a: 1 } ) |
{ a: 1 } |
db.data.find().sort( { a: -1 } ) |
{ a: 1 } |
db.data.find().sort( { a: 1, b: 1 } ) |
{ a: 1, b: 1 } |
db.data.find().sort( { a: -1, b: -1 } ) |
{ a: 1, b: 1 } |
db.data.find().sort( { a: 1, b: 1, c: 1 } ) |
{ a: 1, b: 1, c: 1 } |
db.data.find( { a: { $gt: 4 } } ).sort( { a: 1, b: 1 } ) |
{ a: 1, b: 1 } |
考虑以下示例,其中索引的前缀键同时出现在查询谓词和排序中:
在这种情况下,MongoDB可以使用索引按排序指定的顺序检索文档。如示例所示,查询谓词中的索引前缀可以与排序中的前缀不同。
索引可以支持对索引键模式的非前缀子集进行排序操作。为此,查询必须 在排序键之前的所有前缀键上包含相等条件。
例如,该集合data
具有以下索引:
以下操作可以使用索引来获取排序顺序:
例 | 索引前缀 |
---|---|
db.data.find( { a: 5 } ).sort( { b: 1, c: 1 } ) |
{ a: 1 , b: 1, c: 1 } |
db.data.find( { b: 3, a: 4 } ).sort( { c: 1 } ) |
{ a: 1, b: 1, c: 1 } |
db.data.find( { a: 5, b: { $lt: 3} } ).sort( { b: 1 } ) |
{ a: 1, b: 1 } |
如最后一个操作所示,只有排序子集之前的索引字段在查询文档中必须具有相等条件;其他索引字段可以指定其他条件。
如果查询未在排序规范之前或与之重叠的索引前缀上指定相等条件,则该操作将无法有效使用索引。例如,以下操作指定的排序文档,但查询文档在前面的索引字段和上不包含相等匹配项:{ c: 1 }
a
b
这些操作将不会有效地使用索引,甚至可能不会使用索引来检索文档。{ a: 1, b: 1,
c: 1, d: 1 }
要将索引用于字符串比较,操作还必须指定相同的排序规则。即,具有排序规则的索引不能支持对索引字段进行字符串比较的操作(如果该操作指定了不同的排序规则)。
例如,该集合myColl
在category
具有排序规则语言环境的字符串字段上具有索引"fr"
。
以下查询操作指定与索引相同的排序规则,可以使用索引:
但是,默认情况下使用“简单”二进制整理程序的以下查询操作不能使用索引:
对于索引前缀键不是字符串,数组和嵌入式文档的复合索引,指定其他排序规则的操作仍可以使用索引来支持索引前缀键的比较。
例如,集合myColl
在数字字段score
和price
字符串字段
上具有复合索引category
;使用排序规则语言环境创建索引以
"fr"
进行字符串比较:
使用"simple"
二进制排序规则进行字符串比较的以下操作可以使用索引:
下面的操作使用"simple"
二进制排序规则对索引category
字段进行字符串比较,该操作可以使用索引仅满足查询的一部分:score: 5