Obs! Det här svaret är baserat på MongoDB 3.2.4.
Det är värt att upptäcka användningen av explain()
i MongoDB. explain()
utdata från en fråga (t.ex. db.collection.explain().find(...)
) låter dig kontrollera vilket index som används i en fråga och använda db.collection.explain('executionStats')
kommer också att visa dig om frågan lyckas eller misslyckas på grund av SORT
i minnet begränsning.
$in
En $in
fråga kan ses som en serie jämställdhetsfrågor. Till exempel {a: {$in: [1,3,5]}}
kan ses som {a:1}, {a:3}, {a:5}
. MongoDB kommer att sortera $in
array innan du fortsätter med frågan, så att {$in: [3,5,1]}
är inte annorlunda än {$in: [1,3,5]}
.
Låt oss anta att samlingen har ett index på
{a:1, b:1}
-
Sorterar efter
a
db.coll.find({a: {$in: [1,3,5]}}).sort({a:1})
MongoDB kommer att kunna använda
{a:1,b:1}
index, eftersom den här frågan kan ses som en förening av{a:1}, {a:3}, {a:5}
frågor. Sorterar efter{a:1}
tillåter användning av indexprefix , så MongoDB behöver inte utföra en sortering i minnet.Samma situation gäller även för frågan:
db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({a:1})
sedan
sort({a:1})
använder också indexprefixet (a
i detta fall), enSORT
i minnet steg krävs därför inte. -
Sorterar efter
b
Detta är ett mer intressant fall jämfört med att sortera efter
a
. Till exempel:db.coll.find({a: {$in: [1,3,5]}}).sort({b:1})
explain()
utdata från denna fråga kommer att ha ett steg som heterSORT_MERGE
. Kom ihåg attfind()
del av frågan kan ses som{a:1}, {a:3}, {a:5}
.Frågan
db.coll.find({a:1}).sort({b:1})
behöver inte ha enSORT
i minnet steg på grund av{a:1,b:1}
karaktär index:det vill säga MongoDB kan helt enkelt gå igenom det (sorterade) indexet och returnera dokument sorterade efterb
efter att ha uppfyllt likhetsparametern påa
. Till exempel för varjea
, det finns mångab
som redan är sorterade efterb
på grund av indexet.Använder
$in
, kan den övergripande frågan ses som:db.coll.find({a:1}).sort({b:1})
db.coll.find({a:3}).sort({b:1})
db.coll.find({a:5}).sort({b:1})
- Ta de enskilda frågeresultaten ovan och utför en sammanslagning med värdet
b
. Frågan behöver inte ett sorteringssteg i minnet eftersom de individuella frågeresultaten redan är sorterade efterb
. MongoDB behöver bara slå samman de (redan sorterade) sub-frågeresultaten till ett enda resultat.
På samma sätt är frågan
db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({b:1})
använder också en
SORT_MERGE
steg och är mycket lik frågan ovan. Skillnaden är att de enskilda frågorna matar ut dokument baserat på ett antalb
(istället för varjeb
) för varjea
(som kommer att sorteras efterb
på grund av indexet{a:1,b:1}
). Därför behöver frågan inte ett sorteringssteg i minnet.
$or
För en $or
fråga om att använda ett index, varje klausul i $or
uttryck måste ha ett index kopplat till sig
. Om detta krav är uppfyllt är det möjligt för frågan att använda en SORT_MERGE
steg precis som en $in
fråga. Till exempel:
db.coll.explain().find({$or:[{a:1},{a:3},{a:5}]}).sort({b:1})
kommer att ha en nästan identisk frågeplan, indexanvändning och SORT_MERGE
steg som i $in
exemplet ovan. I huvudsak kan frågan ses som:
db.coll.find({a:1}).sort({b:1})
db.coll.find({a:3}).sort({b:1})
db.coll.find({a:5}).sort({b:1})
- Ta de enskilda frågeresultaten ovan och utför en sammanslagning med värdet
b
.
precis som $in
exempel tidigare.
Men den här frågan:
db.coll.explain().find({$or:[{a:1},{b:1}]}).sort({b:1})
kan inte använda något index (eftersom vi inte har {b:1}
index). Den här frågan kommer att resultera i en samlingsskanning och kommer därför att ha ett sorteringssteg i minnet eftersom inget index används.
Om vi däremot skapar indexet {b:1}
, kommer frågan att fortsätta så här:
db.coll.find({a:1}).sort({b:1})
db.coll.find({b:1}).sort({b:1})
- Ta de enskilda frågeresultaten ovan och utför en sammanslagning med värdet
b
(vilket redan är sorterat vid båda underfrågorna, på grund av indexen{a:1,b:1}
och{b:1}
).
och MongoDB kommer att kombinera resultaten av {a:1}
och {b:1}
frågor och utför en sammanslagning av resultaten. Sammanslagningsprocessen är linjär tid, t.ex. O(n)
.
Sammanfattningsvis i en $or
fråga måste varje term ha ett index, inklusive sort()
skede. Annars måste MongoDB utföra en sortering i minnet.