Vale la pena descubrir el uso de explain()
en MongoDB. El explain()
salida de una consulta (por ejemplo, db.collection.explain().find(...)
) le permite verificar qué índice se usa en una consulta y usar db.collection.explain('executionStats')
también le mostrará si la consulta tiene éxito o falla debido a SORT
en memoria limitación.
$en
Un $in
la consulta se puede considerar como una serie de consultas de igualdad. Por ejemplo, {a: {$in: [1,3,5]}}
podría pensarse como {a:1}, {a:3}, {a:5}
. MongoDB ordenará el $in
array antes de continuar con la consulta, de modo que {$in: [3,5,1]}
no es diferente a {$in: [1,3,5]}
.
Supongamos que la colección tiene un índice de
{a:1, b:1}
-
Ordenar por
a
db.coll.find({a: {$in: [1,3,5]}}).sort({a:1})
MongoDB podrá usar el
{a:1,b:1}
índice, ya que esta consulta se puede considerar como una unión de{a:1}, {a:3}, {a:5}
consultas Ordenar por{a:1}
permite el uso de prefijo de índice , por lo que MongoDB no necesita realizar una ordenación en memoria.La misma situación también se aplica a la consulta:
db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({a:1})
desde
sort({a:1})
también usa el prefijo de índice (a
en este caso), unSORT
en memoria por lo tanto, la etapa no es necesaria. -
Ordenar por
b
Este es un caso más interesante en comparación con la clasificación por
a
. Por ejemplo:db.coll.find({a: {$in: [1,3,5]}}).sort({b:1})
El
explain()
la salida de esta consulta tendrá una etapa llamadaSORT_MERGE
. Recuerda que elfind()
parte de la consulta se puede considerar como{a:1}, {a:3}, {a:5}
.La consulta
db.coll.find({a:1}).sort({b:1})
no necesita tener unSORT
en memoria etapa debido a la naturaleza del{a:1,b:1}
índice:es decir, MongoDB puede simplemente recorrer el índice (ordenado) y devolver documentos ordenados porb
después de satisfacer el parámetro de igualdad ena
. Por ejemplo, para cadaa
, hay muchosb
que ya están ordenados porb
debido al índice.Usando
$in
, la consulta general se puede considerar como:db.coll.find({a:1}).sort({b:1})
db.coll.find({a:3}).sort({b:1})
db.coll.find({a:5}).sort({b:1})
- Tome los resultados de la consulta individual anterior y realice una combinación usando el valor de
b
. La consulta no necesita una etapa de clasificación en memoria porque los resultados de las consultas individuales ya están ordenados porb
. MongoDB solo necesita fusionar los resultados de la subconsulta (ya ordenados) en un solo resultado.
Del mismo modo, la consulta
db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({b:1})
también usa un
SORT_MERGE
etapa y es muy similar a la consulta anterior. La diferencia es que las consultas individuales generan documentos basados en un rango deb
(en lugar de cadab
) para cadaa
(que se ordenará porb
debido al índice{a:1,b:1}
). Por lo tanto, la consulta no necesita una etapa de clasificación en memoria.
$o
Para un $or
consulta para usar un índice, cada cláusula en el $or
la expresión debe tener un índice asociado
. Si se cumple este requisito, es posible que la consulta emplee un SORT_MERGE
escenario como un $in
consulta. Por ejemplo:
db.coll.explain().find({$or:[{a:1},{a:3},{a:5}]}).sort({b:1})
tendrá un plan de consulta, uso de índice y SORT_MERGE
casi idénticos escenario como en el $in
ejemplo anterior. Esencialmente, la consulta se puede pensar como:
db.coll.find({a:1}).sort({b:1})
db.coll.find({a:3}).sort({b:1})
db.coll.find({a:5}).sort({b:1})
- Tome los resultados de la consulta individual anterior y realice una combinación usando el valor de
b
.
como el $in
ejemplo anterior.
Sin embargo, esta consulta:
db.coll.explain().find({$or:[{a:1},{b:1}]}).sort({b:1})
no puede usar ningún índice (ya que no tenemos el {b:1}
índice). Esta consulta dará como resultado un análisis de la colección y, en consecuencia, tendrá una etapa de ordenación en memoria ya que no se utiliza índice.
Sin embargo, si creamos el índice {b:1}
, la consulta procederá como:
db.coll.find({a:1}).sort({b:1})
db.coll.find({b:1}).sort({b:1})
- Tome los resultados de la consulta individual anterior y realice una combinación usando el valor de
b
(que ya está ordenado en ambas subconsultas, debido a los índices{a:1,b:1}
y{b:1}
).
y MongoDB combinará los resultados de {a:1}
y {b:1}
consultas y realizar una fusión en los resultados. El proceso de fusión es un tiempo lineal, p. O(n)
.
En conclusión, en un $or
consulta, cada término debe tener un índice, incluido el sort()
escenario. De lo contrario, MongoDB tendrá que realizar una ordenación en memoria.