Database Manual / Indexes / Strategies

The ESR (Equality, Sort, Range) GuidelineESR(相等、排序、范围)指南

An index that references multiple fields is a compound index. Compound indexes can dramatically improve query response times.引用多个字段的索引是复合索引。复合索引可以显著缩短查询响应时间。

Index keys correspond to document fields. In most cases, applying the ESR (Equality, Sort, Range) Guideline to arrange the index keys helps to create a more efficient compound index.索引键对应于文档字段。在大多数情况下,应用ESR(相等、排序、范围)指南来排列索引键有助于创建更有效的复合索引

Ensure that equality fields always come first. Applying equality to the leading field(s) of the compound index allows you to take advantage of the rest of the field values being in sorted order. Choose whether to use a sort or range field next based on your index's specific needs:确保平等字段始终放在首位。将等式应用于复合索引的前导字段,可以利用按排序顺序排列的其余字段值。根据索引的具体需求,选择接下来是使用排序还是范围字段:

This page introduces the ESR Guideline. For more information on optimizing queries, see explain and Query Plans.本页介绍ESR指南。有关优化查询的更多信息,请参阅explain查询计划

Tip

To force MongoDB to use a particular index, use cursor.hint() (mongosh method) when testing indexes.要强制MongoDB使用特定的索引,请在测试索引时使用cursor.hint()mongosh方法)

Equality相等

"Equality" refers to an exact match on a single value. The following exact match queries scan the cars collection for documents whose model field exactly matches Cordoba.“相等”是指单个值的完全匹配。以下精确匹配查询会扫描cars集合中model字段与Cordoba完全匹配的文档。

db.cars.find( { model: "Cordoba" } )
db.cars.find( { model: { $eq: "Cordoba" } } )

Index searches make efficient use of exact matches to reduce the number of index keys examined. Equality fields must come first. When you use the first part of the index for equality, the rest of the index stays in sorted order.索引搜索有效地利用了精确匹配来减少检查的索引键的数量。平等领域必须放在首位。当您使用索引的第一部分进行相等时,索引的其余部分将保持排序顺序。

An index may have multiple keys for queries with exact matches. The index keys for equality matches can appear in any order. However, to satisfy an equality match with the index, all of the index keys for exact matches must come before any other index fields. MongoDB's search algorithm eliminates any need to arrange the exact match fields in a particular order.一个索引可能有多个键,用于完全匹配的查询。相等匹配的索引键可以以任何顺序出现。但是,为了满足与索引的相等匹配,精确匹配的所有索引键都必须位于任何其他索引字段之前。MongoDB的搜索算法消除了以特定顺序排列精确匹配字段的任何需要。

The more selective the equality matches, the more efficient the indexed query.相等匹配的选择性越高,索引查询的效率就越高。

Sort排序

"Sort" determines the order for results. To avoid in-memory sorts, put sort fields before range in the index.“排序”决定了结果的顺序。为了避免内存中的排序,请将排序字段放在索引的range之前。

An index can support sort operations when the query fields are a subset of the index keys. Sort operations on a subset of the index keys are only supported if the query includes equality conditions for all of the prefix keys that precede the sort keys. For more information, see Sort and Non-prefix Subset of an Index.当查询字段是索引键的子集时,索引可以支持排序操作。仅当查询包含排序键之前所有前缀键的相等条件时,才支持对索引键子集进行排序操作。有关详细信息,请参阅索引的排序和无前缀子集

The following example queries the cars collection. The output is sorted by model:以下示例查询cars集合。输出按model排序:

db.cars.find( { manufacturer: "GM" } ).sort( { model: 1 } )

To improve query performance, create an index on the manufacturer and model fields:要提高查询性能,请在manufacturer(制造商)和model(型号)字段上创建索引:

db.cars.createIndex( { manufacturer: 1, model: 1 } )
  • manufacturer is the first key because it is an equality match.manufacturer(制造商)是第一个键,因为这是一个相等的匹配。
  • model is indexed in the same order ( 1 ) as the query.以与查询相同的顺序(1)进行索引。

Range范围

"Range" filters scan fields. The scan doesn't require an exact match, which means range filters are loosely bound to index keys. To improve query efficiency, limit the range bounds and use equality matches to reduce the number of documents to scan.“范围”筛选器扫描字段。扫描不需要精确匹配,这意味着范围筛选器松散地绑定到索引键。为了提高查询效率,请限制范围界限并使用相等匹配来减少要扫描的文档数量。

Range filters resemble the following:范围筛选器类似于以下内容:

db.cars.find( { price: { $gte: 15000} } )
db.cars.find( { age: { $lt: 10 } } )
db.cars.find( { priorAccidents: { $ne: null } } )

If the range predicate in your query is very selective, place it before the sort fields to reduce the number of sorted documents and allow an in-memory sort.如果查询中的范围谓词非常有选择性,请将其放在排序字段之前,以减少排序文档的数量,并允许在内存中排序。

To avoid an in-memory sort, place the range filter after the sort predicate. For more information on in-memory sorts, see cursor.allowDiskUse().为了避免内存中的排序,请将范围筛选器放在排序谓词之后。有关内存排序的更多信息,请参阅cursor.allowDiskUse()

Additional Considerations其他注意事项

  • Inequality operators such as $ne or $nin are range operators, not equality operators.$ne$nin等不等式运算符是范围运算符,而不是等式运算符。
  • $regex is a range operator.是一个范围运算符。
  • $in:

    • When $in is used alone, it is an equality operator that performs a series of equality matches.当单独使用$in时,它是一个执行一系列相等匹配的相等运算符。
    • When $in is used with .sort():$in.sort()一起使用时:

      • If $in has fewer than 201 array elements, the elements are expanded and then merged in the sort order specified for the index using a SORT_MERGE stage. This improves performance for small arrays. In this case, $in is similar to an equality predicate with ESR.如果$in的数组元素少于201个,则这些元素将被展开,然后使用SORT_MERGE阶段按照为索引指定的排序顺序合并。这提高了小型数组的性能。在这种情况下,$In类似于ESR的等价谓词。
      • If $in has 201 elements or more, the elements are ordered like a range operator. In this case, the performance improvement for small arrays isn't realized. It isn't possible for the subsequent fields in the index to be used for sorting, and $in is similar to a range predicate with ESR.如果$in有201个或更多元素,则元素的排序方式类似于范围运算符。在这种情况下,小型数组的性能改进没有实现。索引中的后续字段不可能用于排序,$in类似于ESR的范围谓词。
      • If you typically use $in operators with small arrays, include them earlier in the index specification. If you typically use large arrays, include $in operators where you would include a range predicate.如果您通常在小数组中使用$in运算符,请在索引规范的前面包含它们。如果您通常使用大型数组,请在包含范围谓词的运算符中包含$in

Note

The $in behavior change at 201 array elements is not guaranteed to stay the same for all MongoDB versions.201个数组元素处的$in行为变化并不能保证所有MongoDB版本都保持不变。

Example示例

The following query searches the cars collection for vehicles manufactured by Ford that cost more than $15,000 dollars. The results are sorted by model:以下查询在cars集合中搜索福特制造的价值超过15000美元的汽车。结果按模型排序:

db.cars.find(
{
manufacturer: 'Ford',
cost: { $gt: 15000 }
} ).sort( { model: 1 } )

The query contains all the elements of the ESR Guideline:该查询包含ESR指南的所有元素:

  • manufacturer: 'Ford' is an equality based match是基于平等的匹配
  • cost: { $gt: 15000 } is a range based match, and是基于范围的匹配,以及
  • model is used for sorting用于排序

Following the ESR guideline, the optimal index for the example query is:根据ESR指南,示例查询的最佳索引为:

{ manufacturer: 1, model: 1, cost: 1 }

Learn More了解更多