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
"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
"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 } )
manufactureris the first key because it is an equality match.modelis indexed in the same order (1) as the query.
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().
Additional Considerations
Inequality operators such as
$neor$ninare range operators, not equality operators.$regexis a range operator.When
$inis used alone, it is an equality operator that performs a series of equality matches.When
$inis used with.sort():If
$inhas fewer than 201 array elements, the elements are expanded and then merged in the sort order specified for the index using aSORT_MERGEstage. This improves performance for small arrays. In this case,$inis similar to an equality predicate with ESR.If
$inhas 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$inis similar to a range predicate with ESR.If you typically use
$inoperators with small arrays, include them earlier in the index specification. If you typically use large arrays, include$inoperators 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.
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:
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 matchcost: { $gt: 15000 }is a range-based matchmodelis used for sorting
Following the ESR guideline, the optimal index for the example query is:
{ manufacturer: 1, model: 1, cost: 1 }
Further Discussion
A number of MongoDB conference presentations discuss the ESR rule in depth.