MongoDBのインデックスは、Bツリー構造に格納され、各インデックスエントリはディスク上の特定の場所を指します。 Bツリー構造を使用するということは、MongoDBインデックスが並べ替えられた順序で格納され、常に順番にトラバースされ、MongoDBがインデックスを介して並べ替えられた順序で一連のドキュメントをフェッチするのに費用がかからないことも意味します。
更新 :Bツリー構造はMMAPv1ストレージエンジンに当てはまりますが、WiredTigerストレージエンジン(MongoDB 3.2以降のデフォルト)では実装が少し異なります。基本的な考え方は同じで、ソートされた順序でインデックスをトラバースする方が安価です。
SORT
クエリのステージ(つまり、メモリ内の並べ替え)は、32MBのメモリ使用に制限されています。 SORT
の場合、クエリは失敗します ステージがこの制限を超えています。この制限は、インデックスの並べ替えられた性質を利用することで回避できるため、MongoDBはsort()
を使用してクエリを返すことができます。 メモリ内ソートを実行せずにパラメータ。
クエリの形が次のようになっていると仮定します:
db.a.find({b:{$gt:100}, c:{$gt:200}}).sort(...)
コレクションa
を使用 インデックスが次のとおりです:
db.a.createIndex({b:1,c:1})
sort()
の場合、2つのシナリオが考えられます。 ステージはクエリで指定されます:
1。 MongoDBはインデックスの並べ替えられた性質を使用できず、メモリ内のSORT
を実行する必要があります ステージ 。
これは、クエリが「インデックスプレフィックス」を使用できない場合の結果です。例:
db.a.find({b:{$gt:100}, c:{$gt:200}}).sort({c:1})
上記のクエリでは、インデックス{b:1,c:1}
次の目的で使用できます:
-
b
を持つドキュメントを照合します{b:{$gt:100}}
の場合は100より大きい クエリの一部。 - ただし、返されたドキュメントが
c
で並べ替えられる保証はありません。 。
したがって、MongoDBはメモリ内ソートを実行する以外に選択肢はありません。 explain()
このクエリの出力にはSORT
が含まれます ステージ。このSORT
ステージは32MBのメモリ使用に制限されます。
2。 MongoDBは、インデックスの並べ替えられた性質を使用できます 。
クエリで次を使用した場合の結果は次のとおりです。
- インデックスの順序に一致するキーを並べ替え、
- インデックスと同じ順序を指定します(つまり、インデックス
{b:1,c:1}
sort({b:1,c:1})
に使用できます またはsort({b:-1,c:-1})
ただし、sort({b:1,c:-1})
ではありません )
例:
db.a.find({b:{$gt:100}, c:{$gt:200}}).sort({b:1})
上記のクエリでは、インデックス{b:1,c:1}
次の目的で使用できます:
-
b
を持つドキュメントを照合します{b:{$gt:100}}
の場合は100より大きい クエリの一部。 - この場合、 MongoDBは、返されたドキュメントが
b
でソートされていることを保証できます。 。
explain()
上記のクエリの出力はありません SORT
があります ステージ。また、 explain()
sort()
がある場合とない場合のクエリの出力 同一です 。本質的に、sort()
を取得しています 無料です。
この主題を理解するための価値のあるリソースは、MongoDB複合インデックスの最適化です。このブログ投稿は2012年に作成されたものであることに注意してください。一部の用語は古くなっている可能性がありますが、投稿の専門性は依然として関連しています。
フォローアップの質問に関する最新情報
-
MongoDBは、ほとんどのクエリに1つのインデックスのみを使用します。したがって、たとえば、メモリ内の
SORT
を回避するには クエリのステージdb.a.find({a:1}).sort({b:1})
インデックスは両方の
a
をカバーする必要があります およびb
同時にフィールド;例えば{a:1,b:1}
などの複合インデックス 必要とされている。 2つの別々のインデックスを持つことはできません{a:1}
および{b:1}
、{a:1}
を期待します 等式部分に使用されるインデックス、および{b:1}
ソート部分に使用されるインデックス。この場合、MongoDBは2つのインデックスのいずれかを選択します。したがって、結果はインデックス順に検索されて返されるため、結果が並べ替えられるのは正しいことです。
-
複合インデックスを使用したメモリ内ソートを回避するには、インデックスの最初の部分が等式部分に対応する必要があります クエリの2番目の部分は並べ替え部分に対応する必要があります クエリの(上記(1)の説明に示されているように)
このようなクエリがある場合:
db.a.find({}).sort({a:1})
インデックス
{a:1,b:1}
並べ替え部分に使用できます(基本的にコレクション全体を返すため)。クエリが次のようになっている場合:db.a.find({a:1}).sort({b:1})
同じインデックス
{a:1,b:1}
クエリの両方の部分に使用することもできます。また:db.a.find({a:1,b:1})
同じインデックスを使用することもできます
{a:1,b:1}
ここのパターンに注意してください:
find()
続いてsort()
パラメータはインデックスの順序に従います{a:1,b:1}
。したがって、複合インデックスは同等->並べ替えで並べ替える必要があります 。
さまざまなタイプの並べ替えに関する更新
フィールドのタイプがドキュメント間で異なる場合(例:a
の場合) あるドキュメントでは文字列、他のドキュメントでは数値、さらに別のドキュメントではブール値)、並べ替えはどのように進行しますか?
答えは、MongoDBBSONタイプの比較順序です。マニュアルページを言い換えると、順序は次のとおりです。
- MinKey(内部タイプ)
- ヌル
- 数値(int、long、double、decimals)
- 記号、文字列
- オブジェクト
- 配列
- BinData
- ObjectId
- ブール値
- 日付
- タイムスタンプ
- 正規表現
- MaxKey(内部タイプ)
したがって、昇順を使用した上記の例から、数字を含むドキュメントが最初に表示され、次に文字列、次にブール値が表示されます。