マルチキー インデックスの限界
項目一覧
インデックスの限界は、インデックスを使用してクエリを実行するときに MongoDB が検索するインデックス値の範囲を定義します。 インデックス付きフィールドに複数のクエリ述語を指定すると、MongoDB はそれらの述語の限界を組み合わせて、より小さな限界のインデックススキャンを生成しようとします。 インデックスの限界が小さいと、クエリが高速化され、リソース使用量が削減されます。
MongoDB は、 の交差または複合限界を利用して限界を組み合わせます。
マルチキー インデックスの限界の交差
限界が交差されている点とは、複数の境界が重複する点を指します。 たとえば、限界が [ [ 3, Infinity ] ]
と[ [
-Infinity, 6 ] ]
の場合、これらの限界の交差は[ [ 3, 6
] ]
になります。
インデックス付き配列フィールドがある場合、配列に複数のクエリ述語を指定し、クエリを実行するためにマルチキー インデックスを使用するクエリを考えてみましょう。 MongoDB は$elemMatch
演算子がクエリ述語に参加する場合、マルチキー インデックスの限界を交差できます。
例: 限界の交差
次の例では、MongoDB が 限界交差 を使用して、クエリする値の範囲を小さくして、クエリのパフォーマンスを向上させる方法を示しています。
マルチキー インデックス の作成
grades
配列にマルチキー インデックスを作成します。
db.students.createIndex( { grades: 1 } )
コレクションをクエリする
次のクエリを実行します。
db.students.find( { grades : { $elemMatch: { $gte: 90, $lte: 99 } } } )
上記のクエリでは、 grades
$elemMatch
を使用して、指定された条件の両方に一致する要素が少なくとも 1 つ含まれているドキュメントを返します。
クエリ述語を個別に取得する
90 以上の述語(
$gte: 90
)の限界は[ [ 90, Infinity ] ]
です。99 以下の述語(
$lte: 99
)の限界は[ [ -Infinity, 99 ] ]
です。
クエリでは$elemMatch
を使用してこれらの述語を結合するため、MongoDB は次のように限界を交差します。
ratings: [ [ 90, 99 ] ]
$elemMatch を使用しないクエリ
クエリが配列フィールドの条件を$elemMatch
と結合しない場合、MongoDB はマルチキー インデックスの限界を交差できません。
次のクエリを考えてみましょう。
db.students.find( { grades: { $gte: 90, $lte: 99 } } )
クエリは、 grades
配列で次の内容を検索します。
少なくとも 1 つの要素が 以上
90
少なくとも 1 つの要素が 以下
99
同じ要素が両方の条件を満たすことができます。
上記のクエリでは$elemMatch
が使用されていないため、MongoDB は境界を交差しません。 代わりに、MongoDB は次のいずれかの限界を使用します。
[ [ 90, Infinity ] ]
[ [ -Infinity, 99 ] ]
MongoDB は、2 つの限界のうちどちらを選択するかについて保証しません。
マルチキー インデックスの複合限界
複合限界は、複合インデックスの複数のキーの限界を組み合わせます。 複数のキーの限界を使用すると、クエリの処理時間が短縮されます。MongoDB では各限界の結果を個別に計算する必要がないためです。
たとえば、次の限界を持つ複合インデックス{ temperature: 1, humidity: 1
}
について考えてみます。
temperature
の限界は[ [ 80, Infinity ] ]
です。humidity
の限界は[ [ -Infinity, 20 ] ]
です。
限界を複合化すると、両方の限界が使用されます。
{ temperature: [ [ 80, Infinity ] ], humidity: [ [ -Infinity, 20 ] ] }
MongoDB が 2 つの限界を複合化できない場合、MongoDB は先頭のフィールドの限界でインデックススキャンを制限します。 この例では、先頭のフィールドはtemperature
であり、制約はtemperature: [
[ 80, Infinity ] ]
です。
例: 非配列フィールドと配列フィールドの複合限界
次の例は、MongoDB が複合限界を使用してより効率的なクエリ制約を定義し、クエリのパフォーマンスを向上させる方法を示しています。
複合マルチキー インデックスの作成
フィールドと フィールドに 複合マルチキー インデックス を作成します。item
ratings
db.survey.createIndex( { item: 1, ratings: 1 } )
コレクションをクエリする
次のクエリを実行します。
db.survey.find( { item: "XYZ", ratings: { $gte: 3 } } )
上記のクエリでは、インデックスの両方のキー( item
とratings
)に条件を指定しています。
述語を個別に取得する。
item: "XYZ"
述語の限界は[ [ "XYZ", "XYZ" ]]
です。ratings: { $gte: 3 }
述語の限界は[ [ 3, Infinity ] ]
です。
MongoDB は、次の組み合わせた境界を使用します。
{ item: [ [ "XYZ", "XYZ" ] ], ratings: [ [ 3, Infinity ] ] }
例: 非配列フィールドと複数の配列フィールドの複合限界
次の例は、インデックスに配列以外のフィールドと複数の配列フィールドが含まれている場合に MongoDB が複合限界を使用する方法を示しています。
コレクションをクエリする
次のクエリを実行します。
db.survey2.find( { item: "XYZ", "ratings.score": { $lte: 5 }, "ratings.by": "anon" } )
述語を個別に取得する。
item: "XYZ"
述語の限界は[ [ "XYZ", "XYZ" ] ]
です。score: { $lte: 5 }
述語の限界は[ [ -Infinity, 5] ]
です。by: "anon"
述語の限界は[ "anon", "anon" ]
です。
MongoDB は、クエリ述語とインデックス キー値に応じて、 item
キーの限界を"ratings.score"
の限界または"ratings.by"
の限界と複合させます。 MongoDB では、 item
フィールドと複合化される限界は保証されません。
MongoDB は、次のいずれかの方法でクエリを実行します。
MongoDB は
item
の限界と"ratings.score"
の限界を複合化します。{ "item" : [ [ "XYZ", "XYZ" ] ], "ratings.score" : [ [ -Infinity, 5 ] ], "ratings.by" : [ [ MinKey, MaxKey ] ] } MongoDB は
item
の限界と"ratings.by"
の限界を複合化します。{ "item" : [ [ "XYZ", "XYZ" ] ], "ratings.score" : [ [ MinKey, MaxKey ] ], "ratings.by" : [ [ "anon", "anon" ] ] }
"ratings.score"
の限界と"ratings.by"
の限界を複合するには、クエリは$elemMatch
を使用する必要があります。
同じ配列の複数のフィールドの複合限界
同じ配列のインデックス キーの限界を複合化するには、次の両方を満たす必要があります。
インデックス キーは、フィールド名まで同じフィールドパスを共有する必要があります。
クエリでは、そのパス上で
$elemMatch
を使用してフィールドに述語を指定する必要があります。
埋め込みドキュメント内のフィールドの場合、ドット付きフィールド名( "a.b.c.d"
など)はd
のフィールドパスになります。 同じ配列のインデックス キーの限界を複合するには、 $elemMatch
が までのパス上にあり、フィールド名自体を除外している必要があります(つまり"a.b.c"
)。
例
次の例は、MongoDB が同じ配列のインデックス キーの限界を組み合わせる方法を示しています。この例では、前の例で使用した survey2
コレクションを使用しています。
コレクションをクエリする
次のクエリを実行します。
db.survey2.find( { ratings: { $elemMatch: { score: { $lte: 5 }, by: "anon" } } } )
上記のクエリでは、 ratings
フィールドで$elemMatch
を使用して、両方の条件に一致する単一の要素が配列に少なくとも 1 つ含まれていることを要求します。
述語を個別に取得する。
score: { $lte: 5 }
述語の限界は[ [ -Infinity, 5 ] ]
です。by: "anon"
述語の限界は[ [ "anon", "anon" ] ]
です。
MongoDB では、2 つの限界が次の限界に複合されています。
{ "ratings.score" : [ [ -Infinity, 5 ] ], "ratings.by" : [ [ "anon", "anon" ] ] }
例: フィールドパスの相違に関する $elemMatch
クエリで共通パスから異なるフィールドに$elemMatch
が指定されている場合、MongoDB は同じ配列のインデックス キーの限界を複合化できません。
次の例は、フィールドパスの除算に関する$elemMatch
を示しています。
サンプル コレクションを入力する
コレクションsurvey3
には、string フィールドitem
と配列フィールドratings
を持つドキュメントが含まれます。
db.survey3.insertMany( [ { _id: 1, item: "ABC", ratings: [ { scores: [ { q1: 2, q2: 4 }, { q1: 3, q2: 8 } ], loc: "A" }, { scores: [ { q1: 2, q2: 5 } ], loc: "B" } ] }, { _id: 2, item: "XYZ", ratings: [ { scores: [ { q1: 7 }, { q1: 2, q2: 8 } ], loc: "B" } ] } ] )
コレクションをクエリする
次のクエリでは、必要なパスにない$elemMatch
を使用します。
db.survey3.find( { ratings: { $elemMatch: { 'scores.q1': 2, 'scores.q2': 8 } } } )
MongoDB はインデックスの限界を複合化することはできず、インデックス スキャン中に"ratings.scores.q2"
フィールドは制約されません。
限界を複合するには、クエリが共通パス"ratings.scores"
で$elemMatch
を使用する必要があります。
db.survey3.find( { 'ratings.scores': { $elemMatch: { 'q1': 2, 'q2': 8 } } } )