複合インデックスは複数のフィールドを参照するため、クエリの応答時間を大幅に改善できます。
ほとんどの場合、ESR(Equality(等価)、Sort(並べ替え)、Range(範囲))のガイドラインを適用してインデックスキーを配置すると、より効率的な複合インデックスが作成されます。
等価フィールドが常に最初に配置されるようにします。最初に等価フィールドを配置すると、残りのインデックスフィールドがソート順で保持されます。インデックスの特定のニーズに基づいて、次にソートするフィールドと範囲フィールドのどちらを使用するかを選択します。
メモリ内ソートを避けることが重要な場合は、範囲フィールドの前にソート フィールドを配置します(ESR)
クエリの範囲述語が非常に選択的である場合は、ソートフィールドの前に配置してください(ERS)
クエリの最適化の詳細については、explain とクエリプランを参照してください。
Tip
インデックスをテストするときに、 MongoDBに特定のインデックスを使用させるには、 cursor.hint() (mongoshメソッド)を使用します。
Equality(等価)
このページの例では、 sample_mflixサンプルデータセット のデータを使用します。このデータセットを自己管理型MongoDBデプロイにロードする 方法の詳細については、「サンプルデータセットをロードする 」を参照してください。サンプルデータベースに変更を加えた場合、このページの例を実行するには、データベースを削除して再作成する必要がある場合があります。
Equality(等価)は、1つの値で完全に一致することを指します。次の完全一致クエリは、movies コレクションをスキャンして title フィールドが Equilibrium と完全に一致するドキュメントを探します。
db.movies.find( { title: "Equilibrium" }, { title: 1, year: 1, cast: 1 } )
[ { _id: ObjectId('573a13a3f29313caabd0c8d2'), year: 2002, title: 'Equilibrium', cast: [ 'Christian Bale', 'Dominic Purcell', 'Sean Bean', 'Christian Kahrmann' ] } ]
db.movies.find( { title: { $eq: "Equilibrium" } }, { title: 1, year: 1, cast: 1 } )
[ { _id: ObjectId('573a13a3f29313caabd0c8d2'), year: 2002, title: 'Equilibrium', cast: [ 'Christian Bale', 'Dominic Purcell', 'Sean Bean', 'Christian Kahrmann' ] } ]
インデックス検索では、検査されたインデックスキーの数を減らすために完全一致が効率的に使用されます。等価フィールドは最初に指定する必要があります。
インデックスには複数の等価キーを含めることができます。これらは相互に対して任意の順序で表示できますが、すべての等価キーはいずれのソート フィールドまたは範囲フィールドに先行する必要があります。
等価一致の選択性が高いほど、インデックス クエリの効率が高くなります。
Sort
Sort(並べ替え)は、結果の順序を決定します。メモリ内でのソートを回避するには、インデックスの範囲の前にソート フィールドを配置します。
インデックスは、ソート キーに先行するすべてのプレフィックス キーに対して等価条件がクエリに含まれている場合にのみ、キーのサブセットに対するソート操作をサポートします。詳細については、ソートとインデックスのプレフィックス以外のサブセット を参照してください。
次の例では、directorsフィールドに "David Lynch" が含まれる映画を moviesコレクションでクエリします。出力は year でソートされます。
db.movies.find( { directors: "David Lynch" }, { title: 1, year: 1 } ).sort( { year: 1 } )
[ { _id: ObjectId('573a1397f29313caabce77d4'), title: 'The Elephant Man', year: 1980 }, { _id: ObjectId('573a1398f29313caabce9091'), title: 'Dune', year: 1984 }, { _id: ObjectId('573a1398f29313caabce9e12'), title: 'Blue Velvet', year: 1986 }, { _id: ObjectId('573a1399f29313caabced630'), year: 1992, title: 'Twin Peaks: Fire Walk with Me' }, { _id: ObjectId('573a139af29313caabcf00f0'), year: 1997, title: 'Lost Highway' }, { _id: ObjectId('573a139ef29313caabcfbc0e'), year: 1999, title: 'The Straight Story' }, { _id: ObjectId('573a139ef29313caabcfbc36'), title: 'Mulholland Drive', year: 2001 }, { _id: ObjectId('573a13b4f29313caabd40a54'), title: 'Inland Empire', year: 2006 } ]
クエリのパフォーマンスを向上させるには、directors フィールドと year フィールドにインデックスを作成します。
db.movies.createIndex( { directors: 1, year: 1 } )
directorsは等価一致であるため、最初のキーです。yearはクエリと同じ順序(1)でインデックス付けされます。
Range(範囲)
「範囲」フィルターは、フィールドをスキャンします。 スキャンでは完全一致は必要ないため、範囲フィルターはインデックス キーに緩やかに結合されます。 クエリの効率を向上させるには、範囲の境界を制限し、等価一致を使用してスキャンするドキュメント数を減らします。
範囲フィルターは次のようになります。
db.movies.find( { runtime: { $gte: 1000 } }, { title: 1, runtime: 1, year: 1, plot: 1 } )
[ { _id: ObjectId('573a1397f29313caabce69db'), plot: 'The economic and cultural growth of Colorado spanning two centuries from the mid-1700s to the late-1970s.', runtime: 1256, title: 'Centennial', year: 1978 }, { _id: ObjectId('573a1399f29313caabcee1aa'), plot: 'A documentary on the history of the sport with major topics including Afro-American players, player/team owner relations and the resilience of the game.', runtime: 1140, title: 'Baseball', year: 1994 } ]
db.movies.find( { year: { $lt: 1900 } }, { title: 1, year: 1, plot: 1 } )
[ { _id: ObjectId('573a139cf29313caabcf560f'), plot: 'Two people kiss.', title: 'The Kiss', year: 1896 }, { _id: ObjectId('573a13a0f29313caabd041db'), plot: 'Two people kiss.', title: 'The Kiss', year: 1896 } ]
db.movies.find( { type: { $ne: "movie" } }, { title: 1, year: 1, type: 1 } )
[ { _id: ObjectId('573a1395f29313caabce2f03'), title: 'The Forsyte Saga', year: 1967, type: 'series' }, { _id: ObjectId('573a1396f29313caabce520d'), title: 'Scenes from a Marriage', year: 1973, type: 'series' }, { _id: ObjectId('573a1396f29313caabce5b86'), title: 'Ironiya sudby, ili S legkim parom!', year: 1975, type: 'series' }, { _id: ObjectId('573a1397f29313caabce6378'), title: 'Sybil', year: 1976, type: 'series' }, { _id: ObjectId('573a1397f29313caabce6443'), title: 'Jesus of Nazareth', year: 1977, type: 'series' } ]
クエリ内の範囲述語が非常に選択的である場合は、ソートされたドキュメントの数を減らし、メモリ内でソートできるようにするために、ソートフィールドの前にそれを配置してください。
メモリ内ソートを回避するには、ソート述語の後に範囲フィルターを配置します。メモリ内ソートの詳細については、cursor.allowDiskUse() を参照してください。
その他の考慮事項
$regexは範囲演算子です。$inを単独で使用した場合、それは一連の等価一致を実行する等価演算子になります。$inを.sort()と併用する場合$inの配列要素が 201 より少ない場合、要素は展開され、SORT_MERGEステージを使用してインデックスに指定されたソート順でマージされます。これにより、小規模な配列のパフォーマンスが向上します。この場合、$inは ESR を持つ等価述語に似ています。$inに 201 以上の要素がある場合、要素は範囲演算子のように順序付けられます。この場合、小さな配列のパフォーマンス向上は実現されません。インデックス内の後続のフィールドはソートに使用することはできず、$inは ESR を持つ範囲述語に似ています。通常、小さな配列で
$in演算子を使用する場合は、早めにインデックス指定に含めます。通常、大きな配列を使用する場合は、範囲述語を含めるには$in演算子を含めます。
注意
201 配列要素での $in の動作の変更は、すべてのMongoDBバージョンで同じであることを保証するものではありません。
例
次のクエリは、moviesコレクションで、directorsフィールドが "David Lynch" で、かつ runtimeフィールドが 130 分未満の映画を検索します。結果は year でソートされます。
db.movies.find( { directors: "David Lynch", runtime: { $lt: 130 } }, { title: 1, year: 1, runtime: 1 } ).sort( { year: 1 } )
[ { _id: ObjectId('573a1397f29313caabce77d4'), runtime: 124, title: 'The Elephant Man', year: 1980 }, { _id: ObjectId('573a1398f29313caabce9e12'), runtime: 120, title: 'Blue Velvet', year: 1986 }, { _id: ObjectId('573a139ef29313caabcfbc0e'), year: 1999, title: 'The Straight Story', runtime: 112 } ]
クエリには、ESR ガイドラインのすべての要素が含まれています。
directors: "David Lynch"は等価ベースの一致ですruntime: { $lt: 130 }は、範囲ベースの一致ですyearはソートに使用されます
ESR ガイドラインに従うと、例クエリに最適なインデックスは次のようになります。
{ directors: 1, year: 1, runtime: 1 }