AI エージェント向け: ドキュメントインデックスは https://www.mongodb.com/ja-jp/docs/llms.txt で利用できます。すべてのページの markdown バージョンは、いずれかの URL パスに .md を追加することで利用できます。

ESR(Equality, Sort, Range)ガイドライン

複合インデックスは複数のフィールドを参照するため、クエリの応答時間を大幅に改善できます。

ほとんどの場合、ESR(Equality(等価)、Sort(並べ替え)、Range(範囲))のガイドラインを適用してインデックスキーを配置すると、より効率的な複合インデックスが作成されます。

等価フィールドが常に最初に配置されるようにします。最初に等価フィールドを配置すると、残りのインデックスフィールドがソート順で保持されます。インデックスの特定のニーズに基づいて、次にソートするフィールドと範囲フィールドのどちらを使用するかを選択します。

  • メモリ内ソートを避けることが重要な場合は、範囲フィールドの前にソート フィールドを配置します(ESR)

  • クエリの範囲述語が非常に選択的である場合は、ソートフィールドの前に配置してください(ERS)

クエリの最適化の詳細については、explain とクエリプランを参照してください。

Tip

インデックスをテストするときに、 MongoDBに特定のインデックスを使用させるには、 cursor.hint() (mongoshメソッド)を使用します。

このページの例では、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(並べ替え)は、結果の順序を決定します。メモリ内でのソートを回避するには、インデックスの範囲の前にソート フィールドを配置します。

インデックスは、ソート キーに先行するすべてのプレフィックス キーに対して等価条件がクエリに含まれている場合にのみ、キーのサブセットに対するソート操作をサポートします。詳細については、ソートとインデックスのプレフィックス以外のサブセット を参照してください。

次の例では、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)でインデックス付けされます。

「範囲」フィルターは、フィールドをスキャンします。 スキャンでは完全一致は必要ないため、範囲フィルターはインデックス キーに緩やかに結合されます。 クエリの効率を向上させるには、範囲の境界を制限し、等価一致を使用してスキャンするドキュメント数を減らします。

範囲フィルターは次のようになります。

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 } ).limit(5)
[ { _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() を参照してください。

  • $ne や $nin などの不等価演算子は、等価演算子ではなく範囲演算子です。

  • $regex は範囲演算子です。

  • $in:

    • $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 }