Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /

The ESR (Equality, Sort, Range) Guideline

A compound index references multiple fields and can dramatically improve query response times.

In most cases, applying the ESR (Equality, Sort, Range) Guideline to arrange the index keys creates a more efficient compound index.

Ensure that equality fields always come first. Placing equality fields first keeps the remaining index fields in sorted order. Choose whether to use a sort or range field next based on your index's specific needs:

  • If avoiding in-memory sorts is critical, place sort fields before range fields (ESR)

  • If your range predicate in the query is very selective, then put it before sort fields (ERS)

For more information on optimizing queries, see explain and Query Plans.

Tip

To force MongoDB to use a particular index, use cursor.hint() (mongosh method) when testing indexes.

"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.

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.

An index can have multiple equality keys. They can appear in any order relative to each other, but all equality keys must precede any sort or range fields.

The more selective the equality matches, the more efficient the indexed query.

"Sort" determines the order for results. To avoid in-memory sorts, put sort fields before range in the index.

An index supports sort operations on a subset of its keys only when the query includes equality conditions on all 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:

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

To improve query performance, create an index on the manufacturer and model fields:

db.cars.createIndex( { manufacturer: 1, model: 1 } )
  • manufacturer is the first key because it is an equality match.

  • model is indexed in the same order ( 1 ) as the query.

"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().

  • Inequality operators such as $ne or $nin are range operators, not equality operators.

  • $regex is a range operator.

  • $in:

    • When $in is used alone, it is an equality operator that performs a series of equality matches.

    • When $in is used with .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.

      • 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.

      • 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.

Note

The $in behavior change at 201 array elements is not guaranteed to stay the same for all MongoDB versions.

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:

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

The query contains all the elements of the ESR Guideline:

  • manufacturer: 'Ford' is an equality-based match

  • cost: { $gt: 15000 } is a range-based match

  • model is used for sorting

Following the ESR guideline, the optimal index for the example query is:

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

A number of MongoDB conference presentations discuss the ESR rule in depth.

Back

Strategies

On this page