Docs Menu
Docs Home
/
MongoDBマニュアル
/ /

マルチキー インデックスの限界

項目一覧

  • マルチキー インデックスの交差
  • マルチキー インデックスの複合限界

インデックス スキャンの限界は、クエリ中に検索するインデックスの部分を定義します。 インデックスに対する複数の述語が存在する場合、MongoDB は交差または複合により、これらの述語の限界を組み合わせて、より小さな限界のスキャンを生成しようとします。

限界のある交差は論理的な結合を指します(つまり 複数の限界の AND )。 たとえば、2 つの限界が[ [ 3, Infinity ] ][ [ -Infinity, 6 ] ]の場合、その限界の交差は[ [ 3, 6 ] ]になります。

インデックスの配列フィールドがある場合、配列に複数の述語を指定し、 マルチキー インデックスを使用できるクエリを考えてみましょう。 MongoDB では、 が述語に結合される場合、 マルチキー $elemMatchインデックス の限界を交差できます。

たとえば、フィールドitemと配列フィールドratingsを持つドキュメントを含むsurveyコレクションを作成します。

db.survey.insertMany(
[
{ _id: 1, item: "ABC", ratings: [ 2, 9 ] },
{ _id: 2, item: "XYZ", ratings: [ 4, 3 ] }
]
)

ratings配列にマルチキー インデックスを作成します。

db.survey.createIndex( { ratings: 1 } )

次のクエリでは、 $elemMatchを使用して、両方の条件に一致する単一の要素が配列に少なくとも 1 つ含まれていることを要求します。

db.survey.find( { ratings : { $elemMatch: { $gte: 3, $lte: 6 } } } )

述語を個別に取得する。

  • 3 以上の述語の限界(つまり $gte: 3 )は[ [ 3, Infinity ] ]です。

  • 6 以下の述語の限界( $lte: 6 )は[ [ -Infinity, 6 ] ]です。

クエリでは$elemMatchを使用してこれらの述語を結合するため、MongoDB は境界を交差して次のようにすることができます。

ratings: [ [ 3, 6 ] ]

クエリが と配列フィールドの条件を満たさ$elemMatch ない 場合、MongoDB はマルチキー インデックスの限界を交差できません。次のクエリを考えてみましょう。

db.survey.find( { ratings : { $gte: 3, $lte: 6 } } )

クエリは、 ratings配列で、3 以上の要素が少なくとも 1 つと 6 以下の要素が少なくとも 1 つ検索します。 単一の要素が両方の条件を満たす必要はないため、MongoDB は境界を交差することはなく[ [ 3, Infinity ] ]または[ [ -Infinity, 6 ] ]のいずれかを使用します。 MongoDB は、これら 2 つの限界のうちどちらを選択するかについて保証しません。

複合限界の設定 とは、複合インデックスの複数のキーに対して限界を使用することを指します。 たとえば、複合インデックス{ a: 1, b: 1 }[ [ 3, Infinity ] ]のフィールドaに限界があり、 [ [ -Infinity, 6 ] ]のフィールドbに限界があると、限界を複合させ、両方の限界を使用します。

{ a: [ [ 3, Infinity ] ], b: [ [ -Infinity, 6 ] ] }

MongoDB が 2 つの限界を複合化できない場合、MongoDB は常にインデックス スキャンを先頭フィールドの限界(この場合はa: [ [ 3, Infinity ] ] )で制限します。

複合マルチキー インデックス を検討します。つまり、インデックス フィールドの 1 つが配列である複合インデックス。 たとえば、フィールドitemと配列フィールドratingsを持つドキュメントを含むsurveyコレクションを作成します。

db.survey.insertMany(
[
{ _id: 1, item: "ABC", ratings: [ 2, 9 ] },
{ _id: 2, item: "XYZ", ratings: [ 4, 3 ] }
]
)

itemフィールドとratingsフィールドに複合インデックスを作成します。

db.survey.createIndex( { item: 1, ratings: 1 } )

次のクエリでは、インデックスの両方のキーに条件を指定します。

db.survey.find( { item: "XYZ", ratings: { $gte: 3 } } )

述語を個別に取得する。

  • item: "XYZ"述語の限界は[ [ "XYZ", "XYZ" ] ]です。

  • ratings: { $gte: 3 }述語の限界は[ [ 3, Infinity ] ]です。

MongoDB は 2 つの限界を複合して、合計された限界を使用することができます。

{ item: [ [ "XYZ", "XYZ" ] ], ratings: [ [ 3, Infinity ] ] }

WiredTiger および インメモリ ストレージ エンジン のみ

マルチキー インデックスでは、MongoDB は、どのインデックス付きフィールドがインデックスをマルチキー インデックスにするかを追跡します。 この情報を追跡することで、MongoDB クエリ エンジンはより厳しいインデックス限界を使用できるようになります。

前述の複合インデックスは、スカラー フィールド[1] itemと配列フィールドratingsにあります。

db.survey.createIndex( { item: 1, ratings: 1 } )

WiredTiger および インメモリ ストレージ エンジンの場合、クエリ操作で複合マルチキー インデックスのインデックス付きスカラー フィールドに対して複数の述語が指定される場合、MongoDB はフィールドの境界を交差します。

たとえば、次の操作では、スカラー フィールドに範囲クエリを指定し、配列フィールドに範囲クエリを指定します。

db.survey.find( {
item: { $gte: "L", $lte: "Z"}, ratings : { $elemMatch: { $gte: 3, $lte: 6 } }
} )

MongoDB は、 itemから[ [ "L", "Z" ] ]への評価と[[3.0, 6.0]]への評価の境界を交差して、次の合計境界を使用します。

"item" : [ [ "L", "Z" ] ], "ratings" : [ [3.0, 6.0] ]

別の例えとして、スカラーフィールドがネストされたドキュメントに属する場所を考えてみましょう。 たとえば、次のドキュメントを含むsurveyコレクションを作成します。

db.survey.insertMany(
[
{ _id: 1, item: { name: "ABC", manufactured: 2016 }, ratings: [ 2, 9 ] },
{ _id: 2, item: { name: "XYZ", manufactured: 2013 }, ratings: [ 4, 3 ] }
]
)

スカラー フィールド"item.name""item.manufactured" 、および配列フィールドratingsに複合マルチキー インデックスを作成します。

db.survey.createIndex( { "item.name": 1, "item.manufactured": 1, ratings: 1 } )

スカラー フィールドでクエリ述語を指定する次の操作を検討してください。

db.survey.find( {
"item.name": "L" ,
"item.manufactured": 2012
} )

このクエリに、MongoDB は次の組み合わせた限界を使用できます。

"item.name" : [ ["L", "L"] ], "item.manufactured" : [ [2012.0, 2012.0] ]

以前のバージョンの MongoDB では、スカラー フィールドのこれらの限界を組み合わせることはできません。

[1] スカラー フィールドとは、値がドキュメントでも配列でもないフィールドです。例: 値がstringまたは整数であるフィールドは、スカラー フィールドです。スカラー フィールドは、フィールド自体が配列またはドキュメントでない限り、ドキュメントにネストされたフィールドであることができます。 たとえば、ドキュメント{ a: { b: { c: 5, d: 5 } } }では、 cdはスカラー フィールドですが、 abはスカラー フィールドではありません。

配列に埋め込みドキュメントが含まれている場合、埋め込みドキュメントに含まれるフィールドにインデックスを付けるには、インデックス仕様でドット付きフィールド名を使用します。 たとえば、埋め込みドキュメントの次の配列があるとします。

ratings: [ { score: 2, by: "mn" }, { score: 9, by: "anon" } ]

scoreフィールドのドット付きフィールド名は"ratings.score"です。

コレクションsurvey2に、フィールドitemと配列フィールドratingsを持つドキュメントが含まれているとします。

{
_id: 1,
item: "ABC",
ratings: [ { score: 2, by: "mn" }, { score: 9, by: "anon" } ]
}
{
_id: 2,
item: "XYZ",
ratings: [ { score: 5, by: "anon" }, { score: 7, by: "wv" } ]
}

非配列フィールドitemと、配列 の 2 つのフィールドratings.scoreratings.by複合インデックスを作成します。

db.survey2.createIndex( { "item": 1, "ratings.score": 1, "ratings.by": 1 } )

次のクエリは、3 つのフィールドすべてに条件を指定します。

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 は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"です。

たとえば、 ratings.scoreフィールドと フィールドに 複合インデックスratings.by を作成します。

db.survey2.createIndex( { "ratings.score": 1, "ratings.by": 1 } )

フィールド"ratings.score""ratings.by"はフィールドパスratingsを共有しています。 次のクエリでは、フィールドratings$elemMatchを使用して、両方の条件に一致する単一の要素が配列に少なくとも 1 つ含まれていることを要求します。

db.survey2.find( { ratings: { $elemMatch: { score: { $lte: 5 }, by: "anon" } } } )

述語を個別に取得する。

  • score: { $lte: 5 }述語の限界は[ -Infinity, 5 ]です。

  • by: "anon"述語の限界は[ "anon", "anon" ]です。

MongoDB は 2 つの限界を複合して、合計された限界を使用することができます。

{ "ratings.score" : [ [ -Infinity, 5 ] ], "ratings.by" : [ [ "anon", "anon" ] ] }

クエリが$elemMatch を持つインデックス付き配列フィールドの条件を満たさ ない 場合、MongoDB はその限界を複合化 できません 。次のクエリを考えてみましょう。

db.survey2.find( { "ratings.score": { $lte: 5 }, "ratings.by": "anon" } )

配列内の単一の埋め込みドキュメントは両方の条件を満たす必要はないため、MongoDB は限界を複合化しませ。 複合インデックスを使用する場合、MongoDB がインデックスのすべてのフィールドを制限できない場合、MongoDB は常にインデックスの先頭フィールドを制限します(この場合は"ratings.score"です)。

{
"ratings.score": [ [ -Infinity, 5 ] ],
"ratings.by": [ [ MinKey, MaxKey ] ]
}

クエリが埋め込みフィールドのパスに$elemMatchを指定していない場合( フィールド名まで)、MongoDB は同じ配列のインデックス キーの限界を複合化できません

たとえば、コレクションsurvey3には、フィールドitemと配列フィールドratingsを持つドキュメントが含まれています。

{
_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" } ]
}

フィールドと フィールドに 複合インデックス を作成します。ratings.scores.q1ratings.scores.q2

db.survey3.createIndex( { "ratings.scores.q1": 1, "ratings.scores.q2": 1 } )

フィールド"ratings.scores.q1""ratings.scores.q2"はフィールドパス"ratings.scores"を共有しており、 $elemMatchはそのパスにある必要があります。

一方、次のクエリでは、 $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 } } } )

戻る

Multikey