update registro por modificar hacer ejemplos documento consultas consulta busquedas avanzadas mongodb sorting indexing time-complexity

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 ( a en este caso), por lo tanto, no se requiere una etapa SORT en la memoria.

  • Ordenando por b

    Este 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 llamada SORT_MERGE . Recuerde que la porción find() 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 etapa SORT en 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 por b después de satisfacer el parámetro de igualdad en a . Por ejemplo, para cada a , hay muchas b que ya están ordenadas por b 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 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 por b . 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_MERGE y es muy similar a la consulta anterior. La diferencia es que las consultas individuales generan documentos basados ​​en un rango de b (en lugar de cada b ) para cada a (que se ordenarán por b debido 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.