3

二重複合インデックス{a:1、b:1}がある場合、 bのみでクエリを実行すると、インデックスは使用されないことは理にかなっています(つまり、クエリでaを「スキップ」することはできません)。ただし、単独でクエリを実行する場合は、インデックスが使用されます。

ただし、トリプルコンパウンドインデックス{a:1、b:1、c:1}が与えられた場合、私のExplainコマンドは、acでクエリを実行するときにインデックスが使用されることを示しています(つまり、クエリでbを「スキップ」できます)。

Mongoはacのクエリでabcインデックスをどのように使用できますか?また、この場合のインデックスはどの程度効果的ですか?

バックグラウンド:

私のユースケースは、a、b、cでクエリを実行したい場合と、a、cでクエリを実行したい場合があります。ここで、a、b、cに1つのインデックスのみを作成する必要がありますか、それともa、cに1つ、a、b、cに1つ作成する必要がありますか?

( cは選択性の高いマルチキーインデックスであるため、a、c、bにインデックスを作成することは意味がありません。)

4

2 に答える 2

3

ボトムライン/tl;dr:等式または不等式についてクエリが実行された場合、インデックスbは「スキップ」できますが、たとえば、での並べ替えの場合はスキップできません。acc

これはとても良い質問です。残念ながら、これに正式に答える詳細なものは見つかりませんでした。このようなクエリのパフォーマンスはここ数年で向上したと思います。そのため、このトピックに関する古い資料は信用できません。

インデックスの選択性と、等式、不等式、および/または並べ替えをクエリするかどうかに依存するため、全体が非常に複雑です。これexplain()が唯一の友達ですが、私が見つけたものは次のとおりです。

警告:今来るのは、実験結果、推論、推測の混合です。私はカイルのアナロジーを過度に伸ばしているかもしれませんし、完全に間違っているかもしれません(そして私のテスト結果が私の推論と大まかに一致しているので不運です)。

Aのインデックスを使用できることは明らかです。これは、Aの選択性によっては、確かに非常に役立ちます。「スキップ」Bは注意が必要な場合とそうでない場合があります。これをカイルの料理本の例と同じように保ちましょう:

French
    Beef
        ...
    Chicken
        Coq au Vin
        Roasted Chicken
    Lamb
        ...
    ...

「シャトーブリアン」というフランス料理を探すように言われたら、インデックスを使用できますA。材料がわからないため、のすべての料理をスキャンする必要がありAます。一方、各カテゴリの料理のリストはインデックスCで並べ替えられていることを知っているので、各材料リストで「Cha」で始まる文字列を探すだけで済みます。50の材料がある場合、1つではなく50のルックアップが必要になりますが、それはすべてのフランス料理をスキャンするよりもはるかに優れています。

私の実験では、この数はの個別の値の数よりもはるかに少なかったb:2を超えることはなかった。ただし、これは単一のコレクションでのみテストしたものであり、おそらくb-indexの選択性に関係している。

しかし、あなたが私にあなたにすべてのフランス料理のアルファベット順にソートされたリストを与えるように頼んだら、私は困っているでしょう。今、上のインデックスCは無価値です、私はそれらすべてのインデックスリストをマージソートする必要があります。そのためには、すべての要素をスキャンする必要があります。

これは私のテストに反映されています。ここにいくつかの簡略化された結果があります。元のコレクションには日時、int、文字列が含まれていますが、物事をシンプルにしたかったので、すべてintになりました。

基本的に、クエリには2つのクラスしかありません。nscanned<= 2 *limitの場合と、コレクション全体(120kドキュメント)をスキャンする必要がある場合です。インデックスは{a, b, c}

// fast (range query on c while skipping b)
> db.Test.find({"a" : 43, "c" : { $lte : 45454 }});
// slow (sorting)
> db.Test.find({"a" : 43, "c" : { $lte : 45454 }}).sort({ "c" : -1});
> db.Test.find({"a" : 43, "c" : { $lte : 45454 }}).sort({ "b" : -1}); 

// fast (can sort on c if b included in the query)
> db.Test.find({"a" : 43, "b" : 7887, "c" : { $lte : 45454 }}).sort({ "c" : -1});

// fast (older tutorials claim this is slow)
> db.Test.find({"a" : {$gte : 43}, "c" : { $lte : 45454 }});

あなたのマイレージは異なります。

于 2012-06-19T00:05:58.267 に答える
1

AとCでのクエリは、Aでのクエリの特殊なケースと見なすことができます(この場合、インデックスが使用されます)。インデックスを使用すると、ドキュメント全体をロードするよりも効率的です。

Aが7〜13、Cが5〜8のすべてのドキュメントを取得したいとします。

Aのみにインデックスがある場合:データベースはインデックスを使用してAが7〜13のドキュメントを選択できますが、Cが5〜8であることを確認するには、対応するドキュメントも取得する必要があります。

A、B、およびCにインデックスがある場合、データベースはそのインデックスを使用して、Aが7〜13のドキュメントを選択できます。Cの値はすでにインデックスのレコードに格納されているため、対応するかどうかを判断できます。ドキュメントもC基準に一致し、それらのドキュメントを取得する必要はありません。したがって、ディスクの読み取りを回避し、パフォーマンスを向上させることができます。

于 2012-06-15T15:03:51.410 に答える