Poznámka: Tato odpověď je založena na MongoDB 3.2.4.
Stojí za to objevit použití explain()
v MongoDB. explain()
výstup dotazu (např. db.collection.explain().find(...)
) umožňuje zkontrolovat, který index je použit v dotazu, a pomocí db.collection.explain('executionStats')
také vám ukáže, zda byl dotaz úspěšný nebo selhal kvůli SORT
v paměti omezení.
$in
$in
dotaz lze považovat za sérii dotazů na rovnost. Například {a: {$in: [1,3,5]}}
lze si představit jako {a:1}, {a:3}, {a:5}
. MongoDB seřadí $in
pole před pokračováním v dotazu, takže {$in: [3,5,1]}
se neliší od {$in: [1,3,5]}
.
Předpokládejme, že kolekce má index
{a:1, b:1}
-
Řazení podle
a
db.coll.find({a: {$in: [1,3,5]}}).sort({a:1})
MongoDB bude moci používat
{a:1,b:1}
index, protože tento dotaz lze považovat za spojení{a:1}, {a:3}, {a:5}
dotazy. Řazení podle{a:1}
umožňuje použití předpony indexu , takže MongoDB nemusí provádět řazení v paměti.Stejná situace platí také pro dotaz:
db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({a:1})
od
sort({a:1})
také používá předponu indexu (a
v tomto případě)SORT
v paměti fáze proto není vyžadována. -
Řazení podle
b
Toto je zajímavější případ ve srovnání s řazením podle
a
. Například:db.coll.find({a: {$in: [1,3,5]}}).sort({b:1})
explain()
výstup tohoto dotazu bude mít fázi nazvanouSORT_MERGE
. Pamatujte, žefind()
část dotazu si lze představit jako{a:1}, {a:3}, {a:5}
.Dotaz
db.coll.find({a:1}).sort({b:1})
nemusí mít v pamětiSORT
fázi kvůli povaze{a:1,b:1}
index:to znamená, že MongoDB může jednoduše projít (seřazený) index a vrátit dokumenty seřazené podleb
po splnění parametru rovnosti naa
. Např. pro každýa
, existuje mnohob
které jsou již seřazeny podleb
kvůli indexu.Pomocí
$in
, celkový dotaz lze považovat za:db.coll.find({a:1}).sort({b:1})
db.coll.find({a:3}).sort({b:1})
db.coll.find({a:5}).sort({b:1})
- Vezměte výsledky jednotlivých dotazů výše a proveďte sloučení pomocí hodnoty
b
. Dotaz nepotřebuje fázi řazení v paměti protože výsledky jednotlivých dotazů jsou již seřazeny podleb
. MongoDB stačí sloučit (již seřazené) výsledky dílčích dotazů do jednoho výsledku.
Podobně dotaz
db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({b:1})
také používá
SORT_MERGE
fázi a je velmi podobný dotazu výše. Rozdíl je v tom, že jednotlivé dotazy vydávají dokumenty na základě rozsahub
(místo každýb
) pro každýa
(které budou seřazeny podleb
kvůli indexu{a:1,b:1}
). Dotaz tedy nepotřebuje fázi řazení v paměti.
$nebo
Pro $or
dotaz na použití indexu, každá klauzule v $or
výraz musí mít přidružený index
. Pokud je tento požadavek splněn, je možné, aby dotaz použil SORT_MERGE
fázi stejně jako $in
dotaz. Například:
db.coll.explain().find({$or:[{a:1},{a:3},{a:5}]}).sort({b:1})
bude mít téměř identický plán dotazů, použití indexu a SORT_MERGE
fázi jako v $in
příklad výše. Dotaz lze v zásadě považovat za:
db.coll.find({a:1}).sort({b:1})
db.coll.find({a:3}).sort({b:1})
db.coll.find({a:5}).sort({b:1})
- Vezměte výsledky jednotlivých dotazů výše a proveďte sloučení pomocí hodnoty
b
.
stejně jako $in
příklad výše.
Tento dotaz však:
db.coll.explain().find({$or:[{a:1},{b:1}]}).sort({b:1})
nelze použít žádný index (protože nemáme {b:1}
index). Tento dotaz bude mít za následek skenování kolekce a následně bude mít fázi řazení v paměti protože není použit žádný index.
Pokud však vytvoříme index {b:1}
, dotaz bude pokračovat takto:
db.coll.find({a:1}).sort({b:1})
db.coll.find({b:1}).sort({b:1})
- Vezměte výsledky jednotlivých dotazů výše a proveďte sloučení pomocí hodnoty
b
(který je již řazen u obou dílčích dotazů, kvůli indexům{a:1,b:1}
a{b:1}
).
a MongoDB zkombinují výsledky {a:1}
a {b:1}
dotazy a provést sloučení výsledků. Proces slučování je lineární čas, kupř. O(n)
.
Na závěr v $or
každý výraz musí mít index, včetně sort()
etapa. Jinak bude muset MongoDB provést řazení v paměti.