Dado que los índices contienen registros ordenados, MongoDB puede obtener los resultados de una clasificación de un índice que incluye los campos de clasificación. MongoDB puede usar varios índices para admitir una operación de ordenación si la ordenación utiliza los mismos índices que el predicado del query.
Si MongoDB no puede utilizar un índice o índices para obtener el orden de clasificación, MongoDB debe realizar una operación de clasificación en memoria sobre los datos.
A partir de MongoDB 6.0, si el servidor requiere más de 100 megabytes de memoria para una etapa de ejecución de canalización, MongoDB escribe automáticamente archivos temporales en el disco a menos que la consulta especifique
{ allowDiskUse: false }.
Las operaciones de ordenación que utilizan un índice a menudo tienen un mejor rendimiento que las ordenaciones en memoria.
Nota
Cuando se ordena en función de un campo de matriz que está indexado con un índice multiclave, el plan de consulta incluye una etapa de ordenamiento en memoria a menos que se cumplan las dos condiciones siguientes:
Ordenar con un índice de campo único
Si hay un índice ascendente o descendente en un solo campo, la operación de clasificación en el campo puede ser en cualquier dirección.
Por ejemplo, crea un índice ascendente en el campo a para una colección records:
db.records.createIndex( { a: 1 } )
Este índice puede admitir un orden ascendente en a:
db.records.find().sort( { a: 1 } )
El índice también puede admitir el siguiente orden descendente en a recorriendo el índice en orden inverso:
db.records.find().sort( { a: -1 } )
Ordenar en múltiples campos
Crea un índice compuesto para admitir la clasificación en varios campos.
Puedes especificar un orden en todas las claves del índice o en un subconjunto; sin embargo, las claves de clasificación deben aparecer en el mismo orden en que aparecen en el índice. Por ejemplo, un patrón de clave de índice { a: 1, b: 1
} puede admitir un orden { a: 1, b: 1 } pero no { b: 1, a:
1 }.
Para que un query utilice un índice compuesto para una ordenación, la dirección de ordenación especificada para todas las claves del documento cursor.sort() debe coincidir con el patrón de claves del índice o coincidir con el inverso del patrón de claves del índice. Por ejemplo, un patrón de clave de índice { a: 1, b: -1 } puede admitir un orden { a: 1, b: -1 } y { a: -1, b: 1 } pero no { a: -1, b: -1 } o {a: 1, b: 1}.
Prefijo de ordenación e índice
Si las claves de ordenación se corresponden con las claves del índice o con un prefijo del índice, MongoDB puede utilizar el índice para ordenar los resultados del query. Un prefijo de un índice compuesto es un subconjunto que consiste en una o más claves al comienzo del patrón de clave de índice.
Por ejemplo, crea un índice compuesto en la colección data:
db.data.createIndex( { a:1, b: 1, c: 1, d: 1 } )
Entonces, estos son los prefijos de ese índice:
{ a: 1 } { a: 1, b: 1 } { a: 1, b: 1, c: 1 }
Las siguientes operaciones de query y ordenación utilizan los prefijos de índice para ordenar los resultados. Estas operaciones no necesitan ordenar el conjunto de resultados en la memoria.
Ejemplo | Index Prefix |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Analiza el siguiente ejemplo en el que las claves de prefijo del índice aparecen tanto en el predicado del query como en el orden:
db.data.find( { a: { $gt: 4 } } ).sort( { a: 1, b: 1 } )
En tales casos, MongoDB puede utilizar el índice para recuperar los documentos en el orden especificado. Como se muestra en el ejemplo, el prefijo de índice en el predicado del query puede ser diferente del prefijo de la ordenación.
Ordenación y subconjunto sin prefijo de un índice
Un índice puede admitir operaciones de ordenación en un subconjunto del patrón de claves de índice que no sea prefijo. Para ello, el query debe incluir condiciones de igualdad en todas las claves de prefijo que preceden a las claves de ordenación.
Por ejemplo, la colección data tiene el siguiente índice:
{ a: 1, b: 1, c: 1, d: 1 }
Las siguientes operaciones pueden utilizar el índice para obtener el orden de ordenación:
Ejemplo | Index Prefix |
|---|---|
|
|
|
|
|
|
Como muestra la última operación, solo los campos de índice que preceden al subconjunto de ordenación deben tener las condiciones de igualdad en el documento de query; los otros campos de índice pueden especificar otras condiciones.
Si el query no especifica una condición de igualdad en un prefijo del índice que preceda o se solape con la especificación de ordenación, la operación no utilizará el índice de manera eficiente. Por ejemplo, las siguientes operaciones especifican un documento de ordenación de { c: 1 }, pero los documentos de query no contienen coincidencias exactas en los campos de índice anteriores a y b:
db.data.find( { a: { $gt: 2 } } ).sort( { c: 1 } ) db.data.find( { c: 5 } ).sort( { c: 1 } )
Estas operaciones no utilizarán el índice { a: 1, b: 1,
c: 1, d: 1 } de forma eficaz y es posible que ni siquiera utilicen el índice para recuperar los documentos.
Orden de ordenación indexada
Una colección de documentos indexados puede tener varios tipos de datos en el campo clave. Cuando un índice tiene una clave con varios tipos de datos, el índice se ordena según el orden de ordenación de tipo BSON.
Consulta el ejemplo de ordenación del índice.
Uso e intercalación del índice
Para utilizar un índice para las comparaciones de cadenas, una operación también debe especificar la misma intercalación. Es decir, un índice con una intercalación no puede soportar una operación que realice comparaciones de strings en los campos indexados si la operación especifica una intercalación diferente.
Advertencia
Debido a que los índices configurados con intercalación utilizan claves de intercalación ICU para lograr el orden de clasificación, las claves de índice que consideran la intercalación pueden ser más grandes que las claves de índice para los índices sin intercalación.
Una colección restaurants tiene los siguientes documentos:
db.restaurants.insertMany( [ { _id: 1, category: "café", status: "Open" }, { _id: 2, category: "cafe", status: "open" }, { _id: 3, category: "cafE", status: "open" } ] )
La colección restaurants tiene un índice en un campo de string category con la intercalación de la localización "fr".
db.restaurants.createIndex( { category: 1 }, { collation: { locale: "fr" } } )
La siguiente query, que especifica la misma intercalación que el índice, puede utilizar el índice:
db.restaurants.find( { category: "cafe" } ).collation( { locale: "fr" } )
Sin embargo, la siguiente operación de query, que por defecto utiliza el intercalador binario "simple", no puede usarse el índice:
db.restaurants.find( { category: "cafe" } )
Para un índice compuesto donde las claves prefijo del índice no son cadenas, arreglos ni documentos incrustados, una operación que especifique una intercalación diferente puede seguir utilizando el índice para soportar comparaciones en las claves prefijo del índice.
Por ejemplo, la colección restaurants tiene un índice compuesto en los campos numéricos score y price y el campo de string category; el índice se crea con la localización de intercalación "fr" para comparaciones de strings:
db.restaurants.createIndex( { score: 1, price: 1, category: 1 }, { collation: { locale: "fr" } } )
Las siguientes operaciones, que utilizan la intercalación binaria "simple" para las comparaciones de strings, pueden usar el índice:
db.restaurants.find( { score: 5 } ).sort( { price: 1 } ) db.restaurants.find( { score: 5, price: { $gt: Decimal128( "10" ) } } ).sort( { price: 1 } )
La siguiente operación, que utiliza la intercalación binaria "simple" para las comparaciones de string en el campo category indexado, puede usar el índice para cumplir solo con la parte score: 5 de la query:
db.restaurants.find( { score: 5, category: "cafe" } )
Para confirmar si una consulta ha utilizado un índice, ejecuta la consulta con la opción explain().
Importante
Las coincidencias con claves de documentos, incluidas las claves de documentos incrustadas, utilizan una comparación binaria simple. Esto significa que una query para una clave como "type.café" no coincidirá con la clave "type.cafe", independientemente del valor que se establezca para el parámetro strength.
Ejemplos
En el siguiente ejemplo, se demuestra la ordenación cuando los tipos de claves de índice son los mismos o son diferentes.
Crear la colección keyTypes:
db.keyTypes.insertMany( [ { seqNum: 1, seqType: null, type: "null" }, { seqNum: 29, seqType: null, type: "null" }, { seqNum: 2, seqType: Int32("10"), type: "Int32" }, { seqNum: 28, seqType: Int32("10"), type: "Int32" }, { seqNum: 3, seqType: Long("10"), type: "Long" }, { seqNum: 27, seqType: Long("10"), type: "Long" }, { seqNum: 4, seqType: Decimal128("10"), type: "Decimal128" }, { seqNum: 26, seqType: Decimal128("10"), type: "Decimal128" }, { seqNum: 5, seqType: Double("10"), type: "Double" }, { seqNum: 25, seqType: Double("10"), type: "Double" }, { seqNum: 6, seqType: String("10"), type: "String" }, { seqNum: 24, seqType: String("10"), type: "String" }, { seqNum: 7, seqType: [ "1", "2", "3" ], type: "Array" }, { seqNum: 23, seqType: [ "1", "2", "3" ], type: "Array" }, { seqNum: 8, seqType: [ [1], [2], [3] ], type: "Array" }, { seqNum: 22, seqType: [ [1], [2], [3] ], type: "Array " }, { seqNum: 9, seqType: [ 1, 2, 3 ], type: "Array" }, { seqNum: 21, seqType: [ 1, 2, 3 ], type: "Array" }, { seqNum: 10, seqType: true, type: "Boolean" }, { seqNum: 11, seqType: new Timestamp(), type: "Timestamp" }, { seqNum: 12, seqType: new Date(), type: "Date" }, { seqNum: 13, seqType: new ObjectId(), type: "ObjectId" }, ] )
Crea índices en los campos de número de secuencia ( seqNum ) y tipo de secuencia ( seqType ):
db.keyTypes.createIndex( { seqNum: 1 } ) db.keyTypes.createIndex( { seqType: 1 } )
Realiza un query en la colección mediante find(). El documento de proyección, { _id: 0 }, suprime el campo _id en la visualización de salida.
db.keyTypes.find( {}, { _id: 0 } )
Los documentos se devuelven en orden de inserción:
{ seqNum: 1, seqType: null, type: 'null' }, { seqNum: 29, seqType: null, type: 'null' }, { seqNum: 2, seqType: 10, type: 'Int32' }, { seqNum: 28, seqType: 10, type: 'Int32' }, { seqNum: 3, seqType: Long("10"), type: 'Long' }, { seqNum: 27, seqType: Long("10"), type: 'Long' }, { seqNum: 4, seqType: Decimal128("10"), type: 'Decimal128' }, // Output truncated
El índice de número de secuencia ( seqNum ) tiene valores del mismo tipo. Utiliza el índice seqNum para realizar un query en la colección keyTypes:
db.keyTypes.find( {}, { _id: 0 } ).sort( { seqNum: 1} )
Las claves seqNum son números enteros. Los documentos se devuelven en orden numérico:
{ seqNum: 1, seqType: null, type: 'null' }, { seqNum: 2, seqType: 10, type: 'Int32' }, { seqNum: 3, seqType: Long("10"), type: 'Long' }, { seqNum: 4, seqType: Decimal128("10"), type: 'Decimal128' }, { seqNum: 5, seqType: 10, type: 'Double' }, { seqNum: 6, seqType: '10', type: 'String' }, { seqNum: 7, seqType: [ '1', '2', '3' ], type: 'Array' }, // Output truncated
El índice de tipo de secuencia ( seqType ) tiene valores de diferentes tipos. Utiliza el índice seqType para realizar un query en la colección keyTypes:
db.keyTypes.find( {}, { _id: 0 } ).sort( { seqType: 1} )
Los documentos se devuelven en el orden de ordenación de tipo BSON:
{ seqNum: 1, seqType: null, type: 'null' }, { seqNum: 29, seqType: null, type: 'null' }, { seqNum: 9, seqType: [ 1, 2, 3 ], type: 'Array' }, { seqNum: 21, seqType: [ 1, 2, 3 ], type: 'Array' }, { seqNum: 2, seqType: 10, type: 'Int32' }, { seqNum: 28, seqType: 10, type: 'Int32' }, { seqNum: 3, seqType: Long("10"), type: 'Long' }, { seqNum: 27, seqType: Long("10"), type: 'Long' }, { seqNum: 4, seqType: Decimal128("10"), type: 'Decimal128' }, { seqNum: 26, seqType: Decimal128("10"), type: 'Decimal128' }, { seqNum: 5, seqType: 10, type: 'Double' }, { seqNum: 25, seqType: 10, type: 'Double' }, { seqNum: 7, seqType: [ '1', '2', '3' ], type: 'Array' }, { seqNum: 23, seqType: [ '1', '2', '3' ], type: 'Array' }, { seqNum: 6, seqType: '10', type: 'String' }, { seqNum: 24, seqType: '10', type: 'String' }, { seqNum: 8, seqType: [ [ 1 ], [ 2 ], [ 3 ] ], type: 'Array' }, { seqNum: 22, seqType: [ [ 1 ], [ 2 ], [ 3 ] ], type: 'Array ' }, { seqNum: 13, seqType: ObjectId("6239e3922604d5a7478df071"), type: 'ObjectId' }, { seqNum: 10, seqType: true, type: 'Boolean' }, { seqNum: 12, seqType: ISODate("2022-03-22T14:56:18.100Z"), type: 'Date' }, { seqNum: 11, seqType: Timestamp({ t: 1647960978, i: 1 }), type: 'Timestamp' }
Los tipos numéricos (Int32, Long, Decimal128, Double) son equivalentes en comparación con otros tipos.
Dentro del tipo BSON de números, se ordenan los tipos numéricos:
Int32
Long
Decimal128
Double