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

¿Cómo funciona la clasificación con un índice en MongoDB?

Los índices en MongoDB se almacenan en una estructura de árbol B, donde cada entrada de índice apunta a una ubicación específica en el disco. El uso de una estructura de árbol B también significa que un índice de MongoDB se almacena en un orden ordenado, siempre se recorre en orden, y es barato para MongoDB obtener una serie de documentos en un orden ordenado a través de índices.

Actualizar :La estructura de árbol B es cierta para el motor de almacenamiento MMAPv1, pero el motor de almacenamiento WiredTiger la implementa de forma ligeramente diferente (predeterminada desde MongoDB 3.2). La idea básica sigue siendo la misma, donde es económico recorrer el índice en un orden ordenado.

UN SORT etapa (es decir, clasificación en memoria) en una consulta está limitada a 32 MB de uso de memoria. Una consulta fallará si SORT etapa supera este límite. Este límite se puede eludir utilizando la naturaleza ordenada de los índices, de modo que MongoDB pueda devolver una consulta con un sort() parámetro sin realizar una ordenación en memoria.

Supongamos que la consulta tiene la forma:

    db.a.find({b:{$gt:100}, c:{$gt:200}}).sort(...)

con colección a teniendo un índice de:

    db.a.createIndex({b:1,c:1})

Hay dos escenarios posibles cuando un sort() la etapa se especifica en la consulta:

1. MongoDB no puede usar la naturaleza ordenada del índice y debe realizar un SORT en memoria escenario .

Este es el resultado si la consulta no puede usar el "prefijo de índice". Por ejemplo:

    db.a.find({b:{$gt:100}, c:{$gt:200}}).sort({c:1})

En la consulta anterior, el índice {b:1,c:1} se puede utilizar para:

  • Hacer coincidir documentos que tengan b mayor que 100 para el {b:{$gt:100}} parte de la consulta.
  • Sin embargo, no hay garantía de que los documentos devueltos estén clasificados en términos de c .

Por lo tanto, MongoDB no tiene más remedio que realizar una ordenación en memoria. El explain() la salida de esta consulta tendrá un SORT escenario. Este SORT la etapa estaría limitada a 32 MB de uso de memoria.

2. MongoDB puede usar la naturaleza ordenada del índice .

Este es el resultado si la consulta usa:

  • Claves de clasificación que coincidan con el orden del índice, y
  • Especifica el mismo orden que el índice (es decir, el índice {b:1,c:1} se puede usar para sort({b:1,c:1}) o sort({b:-1,c:-1}) pero no sort({b:1,c:-1}) )

Por ejemplo:

    db.a.find({b:{$gt:100}, c:{$gt:200}}).sort({b:1})

En la consulta anterior, el índice {b:1,c:1} se puede utilizar para:

  • Hacer coincidir documentos que tengan b mayor que 100 para el {b:{$gt:100}} parte de la consulta.
  • En este caso, MongoDB puede garantizar que los documentos devueltos se clasifiquen en términos de b .

El explain() el resultado de la consulta anterior no tener un SORT escenario. Además, el explain() salida de la consulta con y sin sort() son idénticos . En esencia, estamos obteniendo el sort() gratis.

Un recurso valioso para comprender este tema es Optimización de índices compuestos de MongoDB. Tenga en cuenta que esta publicación de blog se escribió en 2012. Aunque parte de la terminología puede estar desactualizada, el tecnicismo de la publicación sigue siendo relevante.

Actualización sobre preguntas de seguimiento

  1. MongoDB usa solo un índice para la mayoría de las consultas. Entonces, por ejemplo, para evitar un SORT en memoria etapa en la consulta

    db.a.find({a:1}).sort({b:1})
    

    el índice debe cubrir tanto a y b campos al mismo tiempo; p.ej. un índice compuesto como {a:1,b:1} es requerido. No puede tener dos índices separados {a:1} y {b:1} , y espera el {a:1} index que se usará para la parte de igualdad, y el {b:1} índice que se utilizará para la parte de ordenación. En este caso, MongoDB elegirá uno de los dos índices.

    Por lo tanto, es correcto que los resultados se ordenen porque se buscan y se devuelven en el orden del índice.

  2. Para evitar tener una ordenación en memoria usando un índice compuesto, la primera parte del índice debe atender a la parte de igualdad de la consulta, y la segunda parte debe atender a la parte de clasificación de la consulta (como se muestra en la explicación de (1) anterior).

    Si tiene una consulta como esta:

    db.a.find({}).sort({a:1})
    

    el índice {a:1,b:1} se puede usar para la parte de clasificación (ya que básicamente está devolviendo toda la colección). Y si su consulta se ve así:

    db.a.find({a:1}).sort({b:1})
    

    el mismo índice {a:1,b:1} también se puede utilizar para ambas partes de la consulta. También:

    db.a.find({a:1,b:1})
    

    también puede usar el mismo índice {a:1,b:1}

    Observe el patrón aquí:find() seguido de sort() los parámetros siguen el orden del índice {a:1,b:1} . Por lo tanto, un índice compuesto debe ordenarse por igualdad -> ordenar .

Actualización sobre la clasificación de diferentes tipos

Si un campo tiene diferentes tipos entre documentos (por ejemplo, si a es cadena en un documento, número en otros, booleano en otro), ¿cómo procede la ordenación?

La respuesta es el orden de comparación de tipo MongoDB BSON. Parafraseando la página del manual, el orden es:

  1. MinKey (tipo interno)
  2. Nulo
  3. Números (ints, largos, dobles, decimales)
  4. Símbolo, Cadena
  5. Objeto
  6. matriz
  7. BinData
  8. Id. de objeto
  9. Booleano
  10. Fecha
  11. Marca de tiempo
  12. Expresión regular
  13. MaxKey (tipo interno)

Entonces, del ejemplo anterior usando orden ascendente, los documentos que contienen números aparecerán primero, luego las cadenas y luego los booleanos.