注: この回答はMongoDB3.2.4に基づいています。
explain()
の使用法を発見することは価値があります
MongoDBで。 explain()
クエリの出力(例:db.collection.explain().find(...)
)クエリで使用されているインデックスを確認し、 db.collection.explain('executionStats')
また、メモリ内のSORT
が原因でクエリが成功したか失敗したかが表示されます 制限。
$ in
$in
クエリは、一連の等式クエリと考えることができます。例:{a: {$in: [1,3,5]}}
{a:1}, {a:3}, {a:5}
と考えることができます 。 MongoDBは$in
をソートします クエリを続行する前に配列を作成し、{$in: [3,5,1]}
{$in: [1,3,5]}
と同じです 。
コレクションのインデックスが
であると仮定しましょう。{a:1, b:1}
-
a
による並べ替えdb.coll.find({a: {$in: [1,3,5]}}).sort({a:1})
MongoDBは
{a:1,b:1}
を使用できるようになります このクエリは{a:1}, {a:3}, {a:5}
の和集合と考えることができるためインデックス。 クエリ。{a:1}
で並べ替える インデックスプレフィックスの使用を許可します 、したがって、MongoDBはメモリ内の並べ替えを実行する必要はありません。同じ状況がクエリにも当てはまります:
db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({a:1})
sort({a:1})
以降 インデックスプレフィックス(a
)も使用します この場合)、メモリ内のSORT
したがって、ステージは必要ありません。 -
b
による並べ替えこれは、
a
で並べ替えるよりも興味深いケースです。 。例:db.coll.find({a: {$in: [1,3,5]}}).sort({b:1})
explain()
このクエリの出力には、SORT_MERGE
というステージがあります。 。find()
であることを忘れないでください クエリの一部は、{a:1}, {a:3}, {a:5}
と考えることができます。 。クエリ
db.coll.find({a:1}).sort({b:1})
メモリ内のSORT
は必要ありません{a:1,b:1}
の性質によるステージ インデックス:つまり、MongoDBは(ソートされた)インデックスをたどり、b
でソートされたドキュメントを返すことができます。a
の等式パラメータを満たした後 。例:各a
、多くのb
があります すでにb
で並べ替えられています インデックスのため。$in
を使用する 、クエリ全体は次のように考えることができます:-
db.coll.find({a:1}).sort({b:1})
-
db.coll.find({a:3}).sort({b:1})
-
db.coll.find({a:5}).sort({b:1})
- 上記の個々のクエリ結果を取得し、
b
の値を使用してマージを実行します 。クエリはメモリ内の並べ替えステージは必要ありません 個々のクエリ結果はすでにb
で並べ替えられているためです 。 MongoDBは、(既に並べ替えられた)サブクエリの結果を単一の結果にマージする必要があります。
同様に、クエリ
db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({b:1})
SORT_MERGE
も使用します ステージであり、上記のクエリと非常によく似ています。違いは、個々のクエリが範囲に基づいてドキュメントを出力することです。b
(すべての代わりにb
)各a
(b
で並べ替えられます インデックス{a:1,b:1}
による )。したがって、クエリにはメモリ内の並べ替えステージは必要ありません。 -
$または
$or
の場合 インデックスを使用するためのクエリ、すべての句$or
で 式にはインデックスが関連付けられている必要があります
。この要件が満たされている場合、クエリでSORT_MERGE
を使用することができます。 $in
のようなステージ クエリ。例:
db.coll.explain().find({$or:[{a:1},{a:3},{a:5}]}).sort({b:1})
ほぼ同じクエリプラン、インデックスの使用、およびSORT_MERGE
$in
のようにステージングする 上記の例。基本的に、クエリは次のように考えることができます:
-
db.coll.find({a:1}).sort({b:1})
-
db.coll.find({a:3}).sort({b:1})
-
db.coll.find({a:5}).sort({b:1})
- 上記の個々のクエリ結果を取得し、
b
の値を使用してマージを実行します 。
$in
と同じように 前の例。
ただし、このクエリ:
db.coll.explain().find({$or:[{a:1},{b:1}]}).sort({b:1})
インデックスを使用できません ({b:1}
がないため 索引)。このクエリによりコレクションスキャンが実行されるため、メモリ内の並べ替えステージがあります インデックスが使用されていないため。
ただし、インデックスを作成する場合{b:1}
、クエリは次のように進行します:
-
db.coll.find({a:1}).sort({b:1})
-
db.coll.find({b:1}).sort({b:1})
- 上記の個々のクエリ結果を取得し、
b
の値を使用してマージを実行します (インデックス{a:1,b:1}
のため、両方のサブクエリですでに並べ替えられています および{b:1}
。
MongoDBは、{a:1}
の結果を結合します および{b:1}
クエリを実行し、結果に対してマージを実行します。マージプロセスは線形時間です。 O(n)
。
結論として、$or
クエリでは、すべての用語にsort()
を含むインデックスが必要です。 ステージ。そうしないと、MongoDBはメモリ内の並べ替えを実行する必要があります。