La optimización de consultas reduce la cantidad de datos que una consulta debe procesar. Utilice índices, proyecciones y límites de consulta para mejorar el rendimiento y reducir el consumo de recursos. Revise periódicamente el rendimiento de las consultas a medida que crecen las colecciones para determinar cuándo escalar.
Crear índices para brindar soporte a queries
Los índices almacenan los valores de los campos en una estructura de datos independiente. En las operaciones de lectura, MongoDB busca en el índice en lugar de escanear toda la colección. En las operaciones de escritura, MongoDB actualiza tanto la colección como el índice.
Crea índices para tus consultas más frecuentes. Si una consulta busca en varios campos, crea un índice compuesto.
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 en el campo type.
db.inventory.createIndex( { type: 1 } )
[1] En mongosh, usa db.collection.createIndex():
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 de la query mide qué tan bien un predicado de query filtra documentos y determina si las queries pueden utilizar índices de manera efectiva.
Las consultas altamente selectivas coinciden con menos documentos y utilizan los índices de manera más efectiva. Por ejemplo, una coincidencia exacta en
_ides altamente selectiva, ya que sólo puede coincidir con un documento como máximo.Las consultas menos selectivas coinciden con más documentos y utilizan los índices de forma menos eficiente.
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 una regular expression depende de la expresión en sí. Para obtener más detalles, consulta expresiones regulares y uso de índices.
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, considere la siguiente query para devolver sólo los campos timestamp, title, author y abstract.
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 obtener más información,consulte Campos del proyecto que se devolverán desde la consulta.
Ejemplo
Para lograr una query cubierta, se deben indexar los campos proyectados. La regla ESR (Equality, Sort, rango) se aplica al orden de los campos en el índice.
Por ejemplo, considera el siguiente índice en la 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.
La siguiente query aplica la regla ESR para un índice compuesto más eficiente:
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 lotes. Si sabes cuántos resultados necesitas, pasa ese valor al método limit() para reducir el consumo de recursos de red.
Limite los resultados después de ordenar para saber qué documentos se devuelven. Por ejemplo, la siguiente query devuelve solo los 10 resultados más recientes de la colección posts:
db.posts.find().sort( { timestamp : -1 } ).limit(10)
Para obtener más información, consulta limit().
Utilice sugerencias de índices
El optimizador del query selecciona el índice óptimo para una operación específica. Sin embargo, puedes forzar un índice específico usando el método hint(). Esto es útil para las pruebas de rendimiento o cuando un campo aparece en varios índices y necesitas garantizar cuál índice utiliza MongoDB.
Utilizar operaciones del servidor.
Utilice el operador $inc para incrementar o decrementar valores en los documentos. El operador incrementa el valor del campo en el lado del servidor, como alternativa a seleccionar un documento, hacer modificaciones simples en el lado del cliente y luego escribir el documento en el servidor. Además, el operador previene condiciones de carrera cuando múltiples instancias de la aplicación actualizan el mismo campo simultáneamente.
Ejecutar queries cubiertos
Una consulta cubierta es aquella que puede ser satisfecha completamente por un índice sin necesidad de examinar ningún documento. Un índice cubre una consulta cuando se cumplen todas las siguientes condiciones:
Todos los campos de la consulta (incluidos los campos especificados por la aplicación y cualquier campo necesario internamente, como por ejemplo para la fragmentación) forman parte del í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 query, que filtra en type y item y devuelve solo 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 la siguiente colección userdata:
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 abarcar consultas sobre campos que no son matrices si el índice registra qué campo o campos lo convierten en multiclave.
Los índices de múltiples claves no pueden cubrir queries sobre campos de arreglos.
Como ejemplo, consulte consultas cubiertas en la página de índices multikey.
Rendimiento
Las queries cubiertas coinciden con las condiciones de query y devuelven resultados usando solo el índice. Esto es más rápido que recuperar documentos porque las claves del índice son, por lo general, más pequeñas que los documentos y los índices suelen estar en RAM o almacenarse secuencialmente en el disco.
Limitaciones
Tipos de índice
No todos los tipos de índices admiten query cubiertas. Consulte la documentación para el tipo de índice específico.
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 verificar si una query está cubierta, utiliza db.collection.explain() o explain(). Consulte Consultas cubiertas.