Por defecto, las consultas devuelven todos los campos en documentos coincidentes. Si necesita todos los campos, devolver documentos completos será más eficiente que hacer que el servidor manipule el conjunto de resultados con criterios de proyección.
Sin embargo, usar la proyección para limitar los campos para regresar de los resultados de la consulta puede mejorar el rendimiento al:
- eliminar campos innecesarios de los resultados de la consulta (guardar en el ancho de banda de la red)
- limitar los campos de resultados para lograr una consulta cubierta (devolver resultados de consultas indexadas sin obtener documentos completos)
Cuando se utiliza la proyección para eliminar los campos no utilizados, el servidor MongoDB tendrá que recuperar cada documento completo en la memoria (si aún no está allí) y filtrar los resultados para volver. Este uso de la proyección no reduce el uso de memoria o el conjunto de trabajo en el servidor MongoDB, pero puede ahorrar un ancho de banda de red significativo para los resultados de la consulta, dependiendo de su modelo de datos y los campos proyectados.
Una consulta cubierta es un caso especial en el que todos los campos solicitados en un resultado de consulta se incluyen en el índice utilizado, por lo que el servidor no tiene que recuperar el documento completo. Las consultas cubiertas pueden mejorar el rendimiento (evitando recuperar documentos) y el uso de memoria (si otras consultas no requieren recuperar el mismo documento).
Ejemplos
Para fines de demostración a través del mongo
shell, imagine que tiene un documento que se ve así:
db.data.insert({
a: 'webscale',
b: new Array(10*1024*1024).join('z')
})
El campo b
puede representar una selección de valores (o en este caso una cadena muy larga).
A continuación, cree un índice en el {a:1}
que sea un campo de uso común consultado por su caso de uso:
db.data.createIndex({a:1})
Un simple findOne()
sin criterios de proyección devuelve un resultado de consulta que es de aproximadamente 10 MB:
> bsonsize(db.data.findOne({}))
10485805
Agregar la proyección {a:1}
limitará la salida al campo a
y al documento _id
(que se incluye por defecto). El servidor MongoDB todavía está manipulando un documento de 10 MB para seleccionar dos campos, pero el resultado de la consulta ahora es de solo 33 bytes:
> bsonsize(db.data.findOne({}, {a:1}))
33
Esta consulta no está cubierta porque se debe buscar el documento completo para descubrir el _id
valor. El _id
campo se incluye en los resultados de la consulta de forma predeterminada, ya que es el identificador único para un documento, pero _id
no se incluirá en un índice secundario a menos que se agregue explícitamente.
Las métricas totalDocsExamined
y totalKeysExamined
en los explain()
resultados mostrarán cuántos documentos y claves de índice se examinaron:
> db.data.find(
{a:'webscale'},
{a:1}
).explain('executionStats').executionStats.totalDocsExamined
> 1
Esta consulta se puede mejorar usando la proyección para excluir el _id
campo y lograr una consulta cubierta usando solo el {a:1}
índice. La consulta cubierta ya no necesita recuperar un documento de ~ 10 MB en la memoria, por lo que será eficiente tanto en el uso de la red como de la memoria:
> db.data.find(
{a:'webscale'},
{a:1, _id:0}
).explain('executionStats').executionStats.totalDocsExamined
0
> bsonsize(db.data.findOne( {a:'webscale'},{a:1, _id:0}))
21
Tengo consultas lentas de MongoDB. ¿Devolver un subconjunto afecta mi consulta lenta (tengo un índice compuesto en el campo)?
Esto no se puede responder sin el contexto de una consulta específica, un documento de ejemplo y el resultado de la explicación completa. Sin embargo, puede ejecutar algunos puntos de referencia en su propio entorno para la misma consulta con y sin proyección para comparar el resultado. Si su proyección agrega una sobrecarga significativa al tiempo general de ejecución de la consulta (procesamiento y transferencia de resultados), esto puede ser una fuerte pista de que su modelo de datos podría mejorarse.
Si no está claro por qué una consulta es lenta, sería mejor publicar una nueva pregunta con detalles específicos para investigar.