ESR(等价性、排序、范围)规则
引用多个字段的索引是组合索引。组合索引可以显著提高查询响应时间。
索引键对应于文档字段。在大多数情况下,将 ESR(等价性、排序、范围)规则应用于索引键的排列可以帮助创建更高效的 组合索引。
本页面介绍了ESR规则。有关查询优化的更多信息,请参阅explain
和查询计划。
提示
要在测试索引时强制MongoDB使用特定的索引,请使用cursor.hint()。
相等性
“相等性”指的是对单个值的精确匹配。以下精确匹配查询扫描cars
集合,查找其model
字段与Cordoba
完全匹配的文档。
db.cars.find( { model: "Cordoba" } ) db.cars.find( { model: { $eq: "Cordoba" } } )
索引搜索通过有效地使用精确匹配来限制需要检查的文档数量。请将需要精确匹配的字段放在索引的第一位。
索引可能具有多个键,用于具有精确匹配的查询。相等匹配的索引键可以以任何顺序出现。然而,为了满足索引的相等匹配,所有精确匹配的索引键都必须在其他索引字段之前。MongoDB的搜索算法消除了对精确匹配字段进行特定顺序排列的需要。
精确匹配应该是选择性的。为了减少扫描的索引键数量,请确保相等测试至少消除90%的可能文档匹配。
排序
“排序”确定结果顺序。排序遵循相等匹配,因为相等匹配减少了需要排序的文档数量。在相等匹配之后进行排序也允许MongoDB进行非阻塞排序。
索引可以在查询字段是索引键的子集时支持排序操作。只有当查询包含所有前缀键(在排序键之前)的相等条件时,才支持对索引键子集的排序操作。有关更多信息,请参阅索引的排序和非前缀子集。
以下示例查询了cars
集合。输出结果按照model
进行排序。
db.cars.find( { manufacturer: "GM" } ).sort( { model: 1 } )
为了提高查询性能,请在manufacturer
和model
字段上创建索引。
db.cars.createIndex( { manufacturer: 1, model: 1 } )
manufacturer
是第一个键,因为它是一个相等匹配。model
的索引顺序(1
)与查询顺序相同。
范围
"范围"过滤器扫描字段。扫描不需要精确匹配,这意味着范围过滤器与索引键松散关联。为了提高查询效率,请限制范围边界并使用相等匹配来减少扫描的文档数。
范围过滤器类似于以下内容
db.cars.find( { price: { $gte: 15000} } ) db.cars.find( { age: { $lt: 10 } } ) db.cars.find( { priorAccidents: { $ne: null } } )
MongoDB无法对范围过滤器的结果执行索引排序。将范围过滤器放置在排序谓词之后,以便MongoDB可以使用非阻塞索引排序。有关阻塞排序的更多信息,请参阅cursor.allowDiskUse()
。
其他注意事项
$regex
是范围运算符。当单独使用
$in
时,它是一个等于操作符,执行一系列的相等匹配。当使用
$in
和.sort()
如果
$in
有少于 200 个数组元素,元素会被展开并按照索引指定的排序方式合并。这提高了小数组的性能。$in
类似于带有 ESR 的等价谓词。如果
$in
有 200 个或更多的元素,元素会被像范围操作符一样排序。在这种情况下,小数组的性能提升没有实现。索引的后续字段无法提供排序,并且$in
类似于带有 ESR 的范围谓词。如果您通常使用小数组与
$ins
,请在索引规范中将$ins
放得更早。如果您通常使用大数组,请在包含范围谓词的位置包含$ins
。
注意
200 的限制可能会更改,并且不能保证在所有 MongoDB 版本中保持不变。
示例
以下查询搜索 cars
集合中由福特制造的、价格超过 15,000 美元的车辆。结果按型号排序
db.cars.find( { manufacturer: 'Ford', cost: { $gt: 15000 } } ).sort( { model: 1 } )
查询包含 ESR 规则的所有元素
manufacturer: 'Ford'
是基于等价的匹配cost: { $gt: 15000 }
是基于范围匹配,并且model
用于排序
根据 ESR 规则,示例查询的最佳索引是
{ manufacturer: 1, model: 1, cost: 1 }