複合インデックスは複数のフィールドを参照するインデックスです。複合インデックスを使用すると、クエリの応答時間を大幅に改善できます。
インデックス キーは、ドキュメントフィールドに対応します。ほとんどの場合、ESR(Equality(等価)、Sort(並べ替え)、Range(範囲))のガイドラインを適用してインデックスキーを配置すると、より効率的な複合インデックスを作成するのに役立ちます。
等価フィールドが常に最初に配置されるようにします。複合インデックスの先頭フィールドに等価性を適用すると、残りのフィールド値がソート順で利用できます。インデックスの特定のニーズに基づいて、次にソートするフィールドと範囲フィールドのどちらを使用するかを選択します。
- メモリ内ソートを避けることが重要な場合は、範囲フィールドの前にソート フィールドを配置します(ESR) 
- クエリの範囲述語が非常に選択的である場合は、ソートフィールドの前に配置してください(ERS) 
このページでは、ESR ガイドラインを紹介します。クエリの最適化の詳細については、explain とクエリプランを参照してください。
Tip
インデックスをテストするときに、 MongoDBに特定のインデックスを使用させるには、 cursor.hint() (mongoshメソッド)を使用します。
Equality(等価)
Equality(等価)は、1つの値で完全に一致することを指します。次の完全一致クエリは、cars コレクションをスキャンして model フィールドが Cordoba と完全に一致するドキュメントを探します。
db.cars.find( { model: "Cordoba" } ) db.cars.find( { model: { $eq: "Cordoba" } } ) 
インデックス検索では、検査されたインデックスキーの数を減らすために完全一致が効率的に使用されます。等価フィールドは最初に指定する必要があります。インデックスの最初の部分を等価として使用すると、インデックスの残りの部分はソート順のままになります。
インデックスには、完全一致のクエリ用に複数のキーがある場合があります。等価一致のインデックス キーは、任意の順序で表示できます。ただし、インデックスと等価一致させるには、完全一致のすべてのインデックス キーが他のインデックス フィールドより前に配置されている必要があります。MongoDB の検索アルゴリズムでは、完全一致フィールドを特定の順序で配置する必要はありません。
等価一致の選択性が高いほど、インデックス クエリの効率が高くなります。
Sort
Sort(並べ替え)は、結果の順序を決定します。メモリ内でのソートを回避するには、インデックスの範囲の前にソート フィールドを配置します。
インデックスは、クエリ フィールドがインデックス キーのサブセットである場合に、ソート操作をサポートできます。 インデックス キーのサブセットに対するソート操作は、ソート キーに先行するすべてのプレフィックス キーに対する等価条件が、クエリに含まれている場合にのみサポートされます。 詳細については、「ソートとインデックスのプレフィックス以外のサブセット 」を参照してください。
次の例では、cars コレクションをクエリします。出力はmodel でソートされます。
db.cars.find( { manufacturer: "GM" } ).sort( { model: 1 } ) 
クエリのパフォーマンスを向上させるには、manufacturer フィールドと model フィールドにインデックスを作成します。
db.cars.createIndex( { manufacturer: 1, model: 1 } ) 
- manufacturerは等価一致であるため、最初のキーです。
- modelはクエリと同じ順序(- 1)でインデックス付けされます。
Range(範囲)
「範囲」フィルターは、フィールドをスキャンします。 スキャンでは完全一致は必要ないため、範囲フィルターはインデックス キーに緩やかに結合されます。 クエリの効率を向上させるには、範囲の境界を制限し、等価一致を使用してスキャンするドキュメント数を減らします。
範囲フィルターは次のようになります。
db.cars.find( { price: { $gte: 15000} } ) db.cars.find( { age: { $lt: 10 } } ) db.cars.find( { priorAccidents: { $ne: null } } ) 
クエリ内の範囲述語が非常に選択的である場合は、ソートされたドキュメントの数を減らし、メモリ内でソートできるようにするために、ソートフィールドの前にそれを配置してください。
メモリ内ソートを回避するには、ソート述語の後に範囲フィルターを配置します。メモリ内ソートの詳細については、cursor.allowDiskUse() を参照してください。
その他の考慮事項
- $regexは範囲演算子です。
- $inを単独で使用した場合、それは一連の等価一致を実行する等価演算子になります。
- $inを- .sort()と併用する場合- $inの配列要素が 201 より少ない場合、要素は展開され、- SORT_MERGEステージを使用してインデックスに指定されたソート順でマージされます。これにより、小規模な配列のパフォーマンスが向上します。この場合、- $inは ESR を持つ等価述語に似ています。
- $inに 201 以上の要素がある場合、要素は範囲演算子のように順序付けられます。この場合、小さな配列のパフォーマンス向上は実現されません。インデックス内の後続のフィールドはソートに使用することはできず、- $inは ESR を持つ範囲述語に似ています。
- 通常、小さな配列で - $in演算子を使用する場合は、早めにインデックス指定に含めます。通常、大きな配列を使用する場合は、範囲述語を含めるには- $in演算子を含めます。
 
 
注意
201 配列要素での $in の動作の変更は、すべてのMongoDBバージョンで同じであることを保証するものではありません。
例
次のクエリは、cars コレクションで、コストが 15,000 ドルを超える Ford 製の車両を検索します。結果はモデル別にソートされます。
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 }