Make the MongoDB docs better! We value your opinion. Share your feedback for a chance to win $100.
Click here >
Docs Menu
Docs Home
/ /

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 }
)
[
{
_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 }

戻る

Strategies

項目一覧