Remarque : Cette réponse est basée sur MongoDB 3.2.4.
Il est intéressant de découvrir l'utilisation de explain()
dans MongoDB. Le explain()
sortie d'une requête (par exemple db.collection.explain().find(...)
) vous permet de vérifier quel index est utilisé dans une requête et d'utiliser db.collection.explain('executionStats')
vous montrera également si la requête réussit ou échoue en raison de SORT
en mémoire limitation.
en $
Un $in
La requête peut être considérée comme une série de requêtes d'égalité. Par exemple, {a: {$in: [1,3,5]}}
pourrait être considéré comme {a:1}, {a:3}, {a:5}
. MongoDB triera les $in
tableau avant de poursuivre la requête, de sorte que {$in: [3,5,1]}
n'est pas différent de {$in: [1,3,5]}
.
Supposons que la collection a un index de
{a:1, b:1}
-
Trier par
a
db.coll.find({a: {$in: [1,3,5]}}).sort({a:1})
MongoDB pourra utiliser le
{a:1,b:1}
index, puisque cette requête peut être considérée comme une union de{a:1}, {a:3}, {a:5}
requêtes. Trier par{a:1}
permet l'utilisation de préfixe d'index , MongoDB n'a donc pas besoin d'effectuer un tri en mémoire.La même situation s'applique également à la requête :
db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({a:1})
depuis
sort({a:1})
utilise également le préfixe d'index (a
dans ce cas), unSORT
en mémoire étape n'est donc pas nécessaire. -
Trier par
b
C'est un cas plus intéressant par rapport au tri par
a
. Par exemple :db.coll.find({a: {$in: [1,3,5]}}).sort({b:1})
Le
explain()
la sortie de cette requête aura une étape appeléeSORT_MERGE
. Rappelez-vous que lefind()
partie de la requête peut être considérée comme{a:1}, {a:3}, {a:5}
.La requête
db.coll.find({a:1}).sort({b:1})
n'a pas besoin d'avoir unSORT
en mémoire étape en raison de la nature du{a:1,b:1}
index :c'est-à-dire que MongoDB peut simplement parcourir l'index (trié) et renvoyer les documents triés parb
après avoir satisfait le paramètre d'égalité sura
. Par exemple, pour chaquea
, il y a beaucoup deb
qui sont déjà triés parb
grâce à l'index.Utiliser
$in
, la requête globale peut être considérée comme :db.coll.find({a:1}).sort({b:1})
db.coll.find({a:3}).sort({b:1})
db.coll.find({a:5}).sort({b:1})
- Prenez les résultats de requête individuels ci-dessus et effectuez une fusion en utilisant la valeur de
b
. La requête n'a pas besoin d'étape de tri en mémoire car les résultats de la requête individuelle sont déjà triés parb
. MongoDB a juste besoin de fusionner les résultats de la sous-requête (déjà triés) en un seul résultat.
De même, la requête
db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({b:1})
utilise également un
SORT_MERGE
stade et est très similaire à la requête ci-dessus. La différence est que les requêtes individuelles produisent des documents basés sur une plage deb
(au lieu de tousb
) pour chaquea
(qui seront triés parb
en raison de l'indice{a:1,b:1}
). Par conséquent, la requête n'a pas besoin d'une étape de tri en mémoire.
$ou
Pour un $or
requête pour utiliser un index, chaque clause dans le $or
l'expression doit être associée à un index
. Si cette exigence est satisfaite, il est possible que la requête emploie un SORT_MERGE
étape comme un $in
requête. Par exemple :
db.coll.explain().find({$or:[{a:1},{a:3},{a:5}]}).sort({b:1})
aura un plan de requête, une utilisation d'index et SORT_MERGE
presque identiques étape comme dans le $in
exemple ci-dessus. Essentiellement, la requête peut être considérée comme :
db.coll.find({a:1}).sort({b:1})
db.coll.find({a:3}).sort({b:1})
db.coll.find({a:5}).sort({b:1})
- Prenez les résultats de requête individuels ci-dessus et effectuez une fusion en utilisant la valeur de
b
.
tout comme le $in
exemple avant.
Cependant, cette requête :
db.coll.explain().find({$or:[{a:1},{b:1}]}).sort({b:1})
ne peut utiliser aucun index (puisque nous n'avons pas le {b:1}
indice). Cette requête se traduira par une analyse de collection, et par conséquent aura une étape de tri en mémoire puisqu'aucun index n'est utilisé.
Si toutefois nous créons l'index {b:1}
, la requête se déroulera comme :
db.coll.find({a:1}).sort({b:1})
db.coll.find({b:1}).sort({b:1})
- Prenez les résultats de requête individuels ci-dessus et effectuez une fusion en utilisant la valeur de
b
(qui est déjà trié aux deux sous-requêtes, en raison des index{a:1,b:1}
et{b:1}
).
et MongoDB combinera les résultats de {a:1}
et {b:1}
requêtes et effectuer une fusion sur les résultats. Le processus de fusion est un temps linéaire, par ex. O(n)
.
En conclusion, dans un $or
requête, chaque terme doit avoir un index, y compris le sort()
organiser. Sinon, MongoDB devra effectuer un tri en mémoire.