registro - mongodb modificar documento
¿Cómo funciona la clasificación con las consultas `$ or` y` $ in` en MongoDB? (1)
Esta es una continuación de esta pregunta : mira eso para el contexto.
Esta pregunta se refiere a un par de casos especiales de la pregunta vinculada, es decir, cómo funciona la ordenación en MongoDB al usar $in o $or operadores, y cómo garantizar el uso de un índice para clasificar en lugar de ordenar en memoria.
$ en:
Por ejemplo, supongamos que tenemos una colección donde la estructura del documento es
{a: XXX, b: XXX}
... y tenemos un índice compuesto en b en ese orden y queremos ejecutar la consulta
{a: {$in: [4, 6, 2, 1, 3, 10]}, b: {$gt: 1, $lt: 6}}
¿Cómo procedería el género si estuviera en a o b ? $in es una especie de operador de igualdad, pero me parece que un tipo en b con un índice es aún imposible. Una ordenación en el uso de un índice solo es posible si el conjunto $in value se ordena primero, creo, pero no sé si MongoDB lo hace.
$ o:
Como $or consultas, IIUC, se procesan como consultas múltiples y, presumiblemente, pueden usar sus respectivos índices, ¿los resultados ordenados se fusionan de alguna manera o lo hacen $or fuerzan un tipo de todos los resultados en la memoria? Si el primero, ¿cuál es la complejidad temporal de este proceso?
Nota: Esta respuesta se basa en MongoDB 3.2.4.
Vale la pena descubrir el uso de explain() en MongoDB. La salida de explain() 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 muestra si la consulta tiene éxito o falla debido a la limitación de SORT en memoria.
$ en
Una consulta $in se puede considerar como una serie de consultas de igualdad. Por ejemplo, {a: {$in: [1,3,5]}} podría considerarse como {a:1}, {a:3}, {a:5} . MongoDB ordenará el array $in antes de continuar con la consulta, por lo 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}
Ordenando por
db.coll.find({a: {$in: [1,3,5]}}).sort({a:1})MongoDB podrá usar el índice
{a:1,b:1}, ya que esta consulta se puede considerar como una unión de consultas de{a:1}, {a:3}, {a:5}. Ordenar por{a:1}permite el uso del 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})dado que
sort({a:1})también usa el prefijo del índice (aen este caso), por lo tanto, no se requiere una etapaSORTen la memoria.Ordenando por
bEste es un caso más interesante en comparación con ordenar por
a. Por ejemplo:db.coll.find({a: {$in: [1,3,5]}}).sort({b:1})La salida de
explain()de esta consulta tendrá una etapa llamadaSORT_MERGE. Recuerde que la porciónfind()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 una etapaSORTen la memoria debido a la naturaleza del índice{a:1,b:1}: es decir, MongoDB simplemente puede recorrer el índice (ordenado) y devolver documentos ordenados porbdespués de satisfacer el parámetro de igualdad ena. Por ejemplo, para cadaa, hay muchasbque ya están ordenadas porbdebido 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 arriba, y realice una fusión usando el valor de
b. La consulta no necesita una etapa de clasificación en memoria porque los resultados de consulta 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 una etapa
SORT_MERGEy 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án porbdebido al índice{a:1,b:1}). Por lo tanto, la consulta no necesita una etapa de clasificación en memoria.-
$ o
Para que $or consulta utilicen un índice, cada cláusula en la expresión $or debe tener un índice asociado . Si se cumple este requisito, es posible que la consulta emplee una etapa SORT_MERGE igual que una consulta $in . Por ejemplo:
db.coll.explain().find({$or:[{a:1},{a:3},{a:5}]}).sort({b:1})
tendrá un plan de consulta, un uso del índice y SORT_MERGE etapa SORT_MERGE casi idénticos $in ejemplo anterior $in . 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 arriba, y realice una fusión usando el valor de
b.
al igual que el $in ejemplo anterior.
Sin embargo, esta consulta:
db.coll.explain().find({$or:[{a:1},{b:1}]}).sort({b:1})
no se puede usar ningún índice (ya que no tenemos el índice {b:1} ). Esta consulta dará como resultado un escaneo de colección, y en consecuencia tendrá una etapa de clasificación en memoria ya que no se usa ningún índice.
Sin embargo, si creamos el índice {b:1} , la consulta procederá de la siguiente manera:
-
db.coll.find({a:1}).sort({b:1}) -
db.coll.find({b:1}).sort({b:1}) - Tome los resultados de la consulta individual arriba, y realice una fusió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 las consultas {a:1} y {b:1} y realizará una combinación de los resultados. El proceso de fusión es el tiempo lineal, por ejemplo O(n) .
En conclusión, en una consulta $or , cada término debe tener un índice, incluida la etapa sort() . De lo contrario, MongoDB tendrá que realizar una ordenación en memoria.