Docs Menu
Docs Home
/ /

Optimización de consultas

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.

La optimización de queries puede ocurrir tanto durante el desarrollo como más adelante, a medida que cambian el uso y la demanda de datos. A medida que crecen las colecciones, una revisión periódica del rendimiento de las queries puede ayudar a determinar cuándo los clústeres necesitan escalar hacia arriba o hacia afuera.

Los Índices almacenan valores de campos individuales o conjuntos de campos de una colección en una estructura de datos separada. En las operaciones de lectura, permiten que MongoDB realice una búsqueda en el índice para identificar documentos relevantes en lugar de en toda la colección. En las operaciones de escritura, MongoDB debe tanto guardar el cambio en la colección como actualizar el índice.

Crear índices para queries emitidos comúnmente. Si un query busca en varios campos, crear 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 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.

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.

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.

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:

  • type se utiliza para una coincidencia exacta (E), por lo que es el primer campo en el índice.

  • item se utiliza para ordenar (S), por lo que está después de type en el índice.

  • expiryDate se utiliza para una query de rango (R), por lo que es el último campo del índice.

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().

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 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.

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 } }

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.

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.

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.

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.

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.

Cuando se ejecuta en mongos, los índices solo pueden cubrir queries en las colecciones particionadas si el índice contiene la clave de partición.

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.

Volver

Coherencia causal y nivel de confirmación de escritura (write concern)

Obtén una insignia de habilidad

¡Domina "Query Optimization" gratis!

Más información

En esta página