La optimización de queries mejora la eficiencia de las operaciones de lectura al reducir la cantidad de datos que las operaciones de queries deben procesar. Se pueden utilizar índices, proyecciones y límites de queries para mejorar el rendimiento de los queries y reducir el consumo de recursos.
Crear índices para brindar soporte a queries
Crear Índices para consultas frecuentes. Si una consulta busca en varios campos, cree un índice compuesto. Usar un índice mejora el rendimiento, ya que sin él, la consulta debe analizar todos los documentos de la colección.
Por ejemplo, considere la siguiente consulta sobre el type campo en la colección inventory:
let typeValue = <someUserInput>; db.inventory.find( { type: typeValue } );
Para mejorar el rendimiento de esta consulta, agregue un índice a la inventory colección en el type campo. []1 En
mongosh, crea índices usando el db.collection.createIndex() método:
db.inventory.createIndex( { type: 1 } )
Para analizar el rendimiento del query, consultar Interpretar los resultados del plan de ejecución.
| [1] | Para índices de un solo campo, el orden del índice no importa. Para índices compuestos, el orden de los campos impacta a qué query soporta el índice. Para más detalles, se puede consultar Orden de clasificación de índices compuestos. |
Crear queries selectivas
La selectividad del query se refiere a qué tan bien el predicado del query filtra los documentos de una colección. La selectividad del query determina si las queries pueden usar los índices de manera efectiva.
Los queries más selectivos coinciden con un porcentaje menor de documentos. Por ejemplo, una coincidencia exacta en el campo único _id es altamente selectiva, ya que puede coincidir como máximo con un documento.
Los queries menos selectivos coinciden con un porcentaje mayor de documentos y no pueden utilizar los índices de manera eficaz.
Por ejemplo, los operadores de desigualdad $nin y $ne no son muy selectivos, ya que a menudo coinciden con una gran parte del índice. Como resultado, en muchos casos, un query $nin o $ne con un índice puede no tener un mejor desempeño que un query $nin o $ne que debe escanear todos los documentos de una colección.
La selectividad de regular expressions depende de las expresiones en sí mismas. Para aprender más, se puede consultar uso de expresiones regulares e índice.
Solo datos necesarios del proyecto
Cuando se necesita un subconjunto de campos de documentos, se puede mejorar el rendimiento devolviendo solo los campos que son necesarios. Las proyecciones disminuyen el tráfico de red y el tiempo de procesamiento.
Por ejemplo, si el query para la colección posts solo necesita los campos timestamp, title, author y abstract, se deben especificar esos campos en la proyección:
db.posts.find( {}, { timestamp : 1, title : 1, author : 1, abstract : 1} ).sort( { timestamp : -1 } )
Cuando se usa una etapa de agregación $project, normalmente debería ser la última etapa del pipeline y se utiliza para especificar qué campos devolver al cliente.
Usar una etapa $project al principio o en medio de un pipeline para reducir el número de campos que se pasan a las etapas posteriores del pipeline es poco probable que mejore el rendimiento, ya que la base de datos realiza esta optimización automáticamente.
Para aprender más sobre el uso de las proyecciones, consultar Campos de proyecto a devolver del query.
Ejemplo
Para lograr un query cubierto, se deben indexar los campos proyectados. La regla ESR (Equality, Sort, Range) [Igualdad, Orden, Rango] se aplica al orden de los campos en el índice.
Por ejemplo, considerar el siguiente índice en una colección inventory:
db.inventory.createIndex( { type: 1, _id: 1, price: 1, item: 1, expiryDate: 1} )
El query anterior, aunque técnicamente correcto, no está estructurado para optimizar el rendimiento del query.
El siguiente query utiliza la regla ESR (Equality, Sort, Range) [Igualdad, Orden, Rango] para crear un índice compuesto más eficiente y mejorar los tiempos de respuesta del query.
db.inventory.aggregate([ { $match: {type: "food", expiryDate: { $gt: ISODate("2025-07-10T00:00:00Z") }}}, { $sort: { item: 1 }}, { $project: { _id: 1, price: 1} } ])
El índice y el query siguen la regla ESR:
typese utiliza para una coincidencia exacta (E), por lo que es el primer campo en el índice.itemse utiliza para ordenar (S), por lo que está después detypeen el índice.expiryDatese utiliza para una query de rango (R), por lo que es el último campo del índice.
Limitar los resultados del query
Los cursores de MongoDB devuelven resultados en agrupación. Si sabe cuántos resultados se desean, se puede especificar ese valor en el método limit(). Limitar los resultados reduce la demanda sobre los recursos de la red.
En general, limitar los resultados es más útil cuando los resultados están ordenados, de modo que se sepa qué documentos se devolverán. Por ejemplo, si solo se necesitan 10 resultados de la query a la colección posts, se ejecuta el siguiente query:
db.posts.find().sort( { timestamp : -1 } ).limit(10)
Para aprender más sobre cómo limitar los resultados, se puede consultar limit().
Utilice sugerencias de índices
El optimizador del query normalmente selecciona el índice óptimo para una operación específica. Sin embargo, se puede forzar a MongoDB a usar un índice específico usando el método hint(). Utilizar hint() para dar soporte a las pruebas de rendimiento o cuando se puede consultar un campo que aparece en varios índices para garantizar que MongoDB utilice el índice correcto.
Utilizar operaciones del servidor.
Utilizar el operador $inc de MongoDB para incrementar o disminuir valores en los documentos. El operador incrementa el valor del campo en el lado del servidor, como alternativa a seleccionar un documento, realizar modificaciones simples en el cliente y luego guardar todo el documento en el servidor. El operador $inc también puede ayudar a evitar las condiciones de competencia que ocurren cuando dos instancias de la aplicación hacen un query a un documento, incrementan un campo manualmente y guardan todo el documento al mismo tiempo.
Ejecutar queries cubiertos
Un query cubierto es un query que se puede satisfacer en su totalidad mediante un índice y no tiene que examinar ningún documento. Un índice cubre un query cuando se aplican todas las siguientes condiciones:
Todos los campos del query (tanto los especificados por la aplicación como los necesarios internamente, como para fines de partición) son parte de un índice.
Todos los campos devueltos en los resultados están en el mismo índice.
Ningún campo en el query es igual a
null. Por ejemplo, los siguientes predicados de queries no pueden dar lugar a queries cubiertos:{ "field": null }{ "field": { $eq: null } }
Ejemplo
Una colección de inventory tiene el siguiente índice en los campos type y item:
db.inventory.createIndex( { type: 1, item: 1 } )
El índice cubre la siguiente operación que hace queries en los campos type y item y devuelve solo el campo item:
db.inventory.find( { type: "food", item:/^c/ }, { item: 1, _id: 0 } )
Para que el índice especificado cubra el query, el documento de proyección debe especificar explícitamente _id: 0 para excluir el campo _id del resultado, ya que el índice no incluye el campo _id.
Documentos incrustados
Un índice puede cubrir un query sobre campos dentro de documentos incrustados.
Por ejemplo, considere una colección userdata con documentos de la siguiente forma:
db.userdata.insertOne( { _id: 1, user: { login: "tester" } } )
La colección tiene el siguiente índice:
db.userdata.createIndex( { "user.login": 1 } )
El índice { "user.login": 1 } cubre el siguiente query:
db.userdata.find( { "user.login": "tester" }, { "user.login": 1, _id: 0 } )
Nota
Para indexar campos en documentos incrustados, se debe utilizar notación de puntos. Consultar Crear un Índice en un campo incrustado.
Cubrir multiclaves
Los índices multiclave pueden cubrir queries sobre campos que no son arreglos si el índice rastrea qué campo o campos hacen que el índice sea multiclave.
Los índices de múltiples claves no pueden cubrir queries sobre campos de arreglos.
Para ver un ejemplo de un query cubierto con un índice multiclave, se puede consultar Queries cubiertos en la página de índices multiclave.
Rendimiento
Debido a que el índice contiene todos los campos requeridos por el query, MongoDB puede hacer coincidir las condiciones del query y devolver los resultados utilizando solo el índice.
Consultar únicamente el índice puede ser mucho más rápido que consultar documentos fuera del índice. Las claves de índice suelen ser más pequeñas que los documentos que catalogan, y los índices suelen estar disponibles en la RAM o ubicados secuencialmente en el disco.
Limitaciones
Tipos de índice
No todos los tipos de índice pueden cubrir queries. Para obtener detalles sobre el soporte de índices cubiertos, se puede consultar la página de documentación del tipo de índice correspondiente.
Colecciones fragmentadas
Cuando se ejecuta en mongos, los índices solo pueden cubrir queries en las colecciones particionadas si el índice contiene la clave de partición.
Explique los resultados
Para determinar si un query es un query cubierto, se debe utilizar el método db.collection.explain() o el método explain(). Ver Queries cubiertos.