複合インデックスは複数のフィールドを参照するインデックスです。複合インデックスを使用すると、クエリの応答時間を大幅に改善できます。
インデックス キーは、ドキュメントフィールドに対応します。ほとんどの場合、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
の配列要素が200より小さい場合、要素は展開され、インデックスに指定されたソート順でマージされます。 これにより、小規模な配列のパフォーマンスが向上します。$in
は、ESR を持つ等価述語に似ています。$in
に200以上の要素がある場合、要素は範囲演算子のように順序付けられます。 このシナリオでは、小さな配列のパフォーマンス向上は実現されません。 インデックス内の後続のフィールドではソートを提供できず、$in
は ESR 付きの範囲述語に似ています。通常、小さな配列で
$ins
を使用する場合は、インデックス指定に$ins
を早めに含めます。通常、大きな配列を使用する場合は、範囲述語を含める場所に$ins
を含めます。
注意
200の制限は変更される可能性があり、すべての 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 }