ボトムライン/tl;dr:等式または不等式についてクエリが実行された場合、インデックスb
は「スキップ」できますが、たとえば、での並べ替えの場合はスキップできません。a
c
c
これはとても良い質問です。残念ながら、これに正式に答える詳細なものは見つかりませんでした。このようなクエリのパフォーマンスはここ数年で向上したと思います。そのため、このトピックに関する古い資料は信用できません。
インデックスの選択性と、等式、不等式、および/または並べ替えをクエリするかどうかに依存するため、全体が非常に複雑です。これ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 }});
あなたのマイレージは異なります。