Nota: Questa risposta si basa su MongoDB 3.2.4.
Vale la pena scoprire l'uso di explain()
in MongoDB. Il explain()
output di una query (ad es. db.collection.explain().find(...) ) consente di verificare quale indice viene utilizzato in una query e di utilizzare db.collection.explain('executionStats')
ti mostrerà anche se la query ha esito positivo o negativo a causa di SORT in memoria limitazione.
$ in
Un $in query può essere considerata come una serie di query di uguaglianza. Ad esempio, {a: {$in: [1,3,5]}} potrebbe essere pensato come {a:1}, {a:3}, {a:5} . MongoDB ordinerà $in array prima di procedere con la query, in modo che {$in: [3,5,1]} non è diverso da {$in: [1,3,5]} .
Supponiamo che la raccolta abbia un indice di
{a:1, b:1}
-
Ordinamento per
adb.coll.find({a: {$in: [1,3,5]}}).sort({a:1})MongoDB sarà in grado di utilizzare il
{a:1,b:1}index, poiché questa query può essere considerata come un'unione di{a:1}, {a:3}, {a:5}interrogazioni. Ordinamento per{a:1}consente l'uso di prefisso indice , quindi MongoDB non ha bisogno di eseguire un ordinamento in memoria.La stessa situazione vale anche per la query:
db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({a:1})poiché
sort({a:1})usa anche il prefisso dell'indice (ain questo caso), unSORTin memoria la fase non è quindi richiesta. -
Ordinamento per
bQuesto è un caso più interessante rispetto all'ordinamento per
a. Ad esempio:db.coll.find({a: {$in: [1,3,5]}}).sort({b:1})Il
explain()l'output di questa query avrà una fase denominataSORT_MERGE. Ricorda che ilfind()parte della query può essere considerata come{a:1}, {a:3}, {a:5}.La query
db.coll.find({a:1}).sort({b:1})non è necessario avere unSORTin memoria fase a causa della natura del{a:1,b:1}index:ovvero, MongoDB può semplicemente percorrere l'indice (ordinato) e restituire documenti ordinati perbdopo aver soddisfatto il parametro di uguaglianza sua. Ad esempio, per ognia, ci sono moltibche sono già ordinati perba causa dell'indice.Usando
$in, la query complessiva può essere considerata come:db.coll.find({a:1}).sort({b:1})db.coll.find({a:3}).sort({b:1})db.coll.find({a:5}).sort({b:1})- Prendi i risultati della singola query sopra ed esegui un'unione utilizzando il valore di
b. La query non necessita di una fase di ordinamento in memoria perché i risultati delle singole query sono già ordinati perb. MongoDB ha solo bisogno di unire i risultati della sottoquery (già ordinati) in un unico risultato.
Allo stesso modo, la query
db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({b:1})utilizza anche un
SORT_MERGEstage ed è molto simile alla query precedente. La differenza è che le singole query generano documenti in base a un intervallo dib(anziché ognib) per ognia(che sarà ordinato perba causa dell'indice{a:1,b:1}). Pertanto, la query non necessita di una fase di ordinamento in memoria.
$o
Per un $or query per utilizzare un indice, ogni clausola nel $or l'espressione deve avere un indice associato
. Se questo requisito è soddisfatto, è possibile che la query utilizzi un SORT_MERGE stage proprio come un $in interrogazione. Ad esempio:
db.coll.explain().find({$or:[{a:1},{a:3},{a:5}]}).sort({b:1})
avrà un piano di query, un utilizzo dell'indice e SORT_MERGE quasi identici come in $in esempio sopra. In sostanza, la query può essere pensata come:
db.coll.find({a:1}).sort({b:1})db.coll.find({a:3}).sort({b:1})db.coll.find({a:5}).sort({b:1})- Prendi i risultati della singola query sopra ed esegui un'unione utilizzando il valore di
b.
proprio come il $in esempio prima.
Tuttavia, questa domanda:
db.coll.explain().find({$or:[{a:1},{b:1}]}).sort({b:1})
non è possibile utilizzare alcun indice (dal momento che non abbiamo il {b:1} indice). Questa query risulterà in una scansione della raccolta e, di conseguenza, avrà una fase di ordinamento in memoria poiché non viene utilizzato alcun indice.
Se, invece, creiamo l'indice {b:1} , la query procederà come:
db.coll.find({a:1}).sort({b:1})db.coll.find({b:1}).sort({b:1})- Prendi i risultati della singola query sopra ed esegui un'unione utilizzando il valore di
b(che è già ordinato in entrambe le sottoquery, a causa degli indici{a:1,b:1}e{b:1}).
e MongoDB combineranno i risultati di {a:1} e {b:1} query ed eseguire un'unione sui risultati. Il processo di fusione è tempo lineare, ad es. O(n) .
In conclusione, in un $or query, ogni termine deve avere un indice, incluso sort() palcoscenico. In caso contrario, MongoDB dovrà eseguire un ordinamento in memoria.