複合インデックスは複数のフィールドを参照するため、クエリの応答時間を大幅に改善できます。
ほとんどの場合、ESR(Equality(等価)、Sort(並べ替え)、Range(範囲))のガイドラインを適用してインデックスキーを配置すると、より効率的な複合インデックスが作成されます。
等価フィールドが常に最初に配置されるようにします。最初に等価フィールドを配置すると、残りのインデックスフィールドがソート順で保持されます。インデックスの特定のニーズに基づいて、次にソートするフィールドと範囲フィールドのどちらを使用するかを選択します。
メモリ内ソートを避けることが重要な場合は、範囲フィールドの前にソート フィールドを配置します(ESR)
クエリの範囲述語が非常に選択的である場合は、ソートフィールドの前に配置してください(ERS)
クエリの最適化の詳細については、explain とクエリプランを参照してください。
Tip
インデックスをテストするときに、 MongoDBに特定のインデックスを使用させるには、 cursor.hint() (mongoshメソッド)を使用します。
Equality(等価)
Equality(等価)は、1つの値で完全に一致することを指します。次の完全一致クエリは、cars コレクションをスキャンして model フィールドが Cordoba と完全に一致するドキュメントを探します。
db.cars.find( { model: "Cordoba" } ) db.cars.find( { model: { $eq: "Cordoba" } } )
インデックス検索では、検査されたインデックスキーの数を減らすために完全一致が効率的に使用されます。等価フィールドは最初に指定する必要があります。
インデックスには複数の等価キーを含めることができます。これらは相互に対して任意の順序で表示できますが、すべての等価キーはいずれのソート フィールドまたは範囲フィールドに先行する必要があります。
等価一致の選択性が高いほど、インデックス クエリの効率が高くなります。
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 }
さらなる議論
MongoDB カンファレンスのプレゼンテーションの多くが、ESR ルールについて深く論じています。