sql >> Base de Datos >  >> NoSQL >> MongoDB

¿Cómo funciona la clasificación con consultas `$or` y `$in` en MongoDB?

Nota: Esta respuesta se basa en MongoDB 3.2.4.

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), un SORT 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 llamada SORT_MERGE . Recuerda que el find() 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 un SORT 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 por b después de satisfacer el parámetro de igualdad en a . Por ejemplo, para cada a , hay muchos b que ya están ordenados 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 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 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 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 de b (en lugar de cada b ) para cada a (que se ordenará 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 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.