ESR(Equality, Sort, Range)ルール
複合インデックスは複数のフィールドを参照するインデックスです。複合インデックスを使用すると、クエリの応答時間を大幅に改善できます。
インデックス キーは、ドキュメント フィールドに対応します。ほとんどの場合、ESR(Equality(等価)、Sort(並べ替え)、Range(範囲))のルールを適用してインデックス キーを配置すると、より効率的な複合インデックスを作成するのに役立ちます。
このページでは、ESR ルールを紹介します。 クエリの最適化の詳細については、 explain
とクエリプラン を参照してください。
Tip
インデックスをテストするときに、MongoDBに特定のインデックスを使用させるには、cursor.hint()を使用します。
Equality(等価)
Equality(等価)は、1つの値で完全に一致することを指します。次の完全一致クエリは、cars
コレクションをスキャンして model
フィールドが Cordoba
と完全に一致するドキュメントを探します。
db.cars.find( { model: "Cordoba" } ) db.cars.find( { model: { $eq: "Cordoba" } } )
インデックス検索では、完全一致を効率的に使用して、クエリを完了するために検査する必要があるドキュメントの数を減らします。 完全一致が必要なフィールドをインデックスの最初に配置します。
インデックスには、完全一致のクエリ用に複数のキーがある場合があります。等価一致のインデックス キーは、任意の順序で表示できます。ただし、インデックスと等価一致させるには、完全一致のすべてのインデックス キーが他のインデックス フィールドより前に配置されている必要があります。MongoDB の検索アルゴリズムでは、完全一致フィールドを特定の順序で配置する必要はありません。
完全一致は選択的である必要があります。スキャンされるインデックス キーの数を減らすには、等価テストで一致する可能性のあるドキュメントの 90% 以上を排除されるようにください。
Sort
Sort(並べ替え)は、結果の順序を決定します。等価一致によって並べ替えが必要なドキュメントの数が減るため、並べ替えは等価一致の後にします。等価一致の後に並べ替えすることで、MongoDB はノンブロッキングソートを行うこともできます。
インデックスは、クエリ フィールドがインデックス キーのサブセットである場合に、ソート操作をサポートできます。 インデックス キーのサブセットに対するソート操作は、ソート キーに先行するすべてのプレフィックス キーに対する等価条件が、クエリに含まれている場合にのみサポートされます。 詳細については、「ソートとインデックスのプレフィックス以外のサブセット 」を参照してください。
次の例では、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 } } )
MongoDB は、範囲フィルターの結果に対してインデックスソートを実行できません。 MongoDB が非ブロッキングインデックスソートを使用できるように、ソート述語の後に範囲フィルターを配置します。 ブロッキングソートの詳細については、 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 }
さらなる議論
MongoDB カンファレンスのプレゼンテーションの多くが、ESR ルールについて深く論じています。