¿Cómo afecta la proyección mongoDB al rendimiento?

10

De la MongoDBdocumentación se menciona que:

Cuando solo necesita un subconjunto de campos de documentos, puede lograr un mejor rendimiento devolviendo solo los campos que necesita

¿Cómo afectan los campos de filtrado al rendimiento? ¿El rendimiento está relacionado con el tamaño de los datos que se transmiten a través de la red? o el tamaño de los datos que se guardarán en la memoria? ¿Cómo se mejora exactamente este rendimiento? ¿Cuál es este rendimiento que se menciona en la documentación?

Tengo consultas lentas de MongoDB. ¿Devolver un subconjunto afecta mi consulta lenta (tengo un índice compuesto en el campo)?

ALH
fuente
Sin el código, no es posible sugerirle. qué afectará realmente el rendimiento en la consulta de proyección "MongoDB". Siempre es mejor al menos mencionar el código.
Md Haidar Ali Khan
@MdHaidarAliKhan no se trata del código y mi carga útil. Solo quiero saber por qué mongoDB dice que el filtrado afecta el rendimiento. ¿Desde qué punto de vista se ha medido este rendimiento? Por ejemplo, ayuda en el uso de la memoria de Mongo debido a que hay menos datos o menos E / S de disco (por ejemplo), etc.
ALH
Solo quiero saber por qué mongoDB dice que el filtrado afecta el rendimiento. bueno, use las proyecciones para devolver solo los datos necesarios, quiero decir que puede lograr un mejor rendimiento devolviendo solo los campos que necesita. Por ejemplo db.posts.find ({}, {}). Sort ({}).
Md Haidar Ali Khan
, Por ejemplo, ¿ayuda en el uso de la memoria de Mongo debido a la menor cantidad de datos o menos E / S de disco (por ejemplo) y así sucesivamente, bueno ... ¿podría actualizar qué versión de MongoDB y sistema operativo en su entorno?
Md Haidar Ali Khan
@MdHaidarAliKhan OS es Debian 8,MongoDB 3.6.2
ALH

Respuestas:

15

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 mongoshell, imagine que tiene un documento que se ve así:

db.data.insert({
    a: 'webscale',
    b: new Array(10*1024*1024).join('z')
})

El campo bpuede 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 ay 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 _idvalor. El _idcampo se incluye en los resultados de la consulta de forma predeterminada, ya que es el identificador único para un documento, pero _idno se incluirá en un índice secundario a menos que se agregue explícitamente.

Las métricas totalDocsExaminedy totalKeysExamineden 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 _idcampo 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.

Stennie
fuente
1
Realmente aprecio la explicación detallada del problema. Parece que no es posible tener consultas cubiertas ya que mi respuesta tiene muchos más datos que dentro del índice. Mi pregunta principal es aquí, estaría feliz si pudieran echar un vistazo: dba.stackexchange.com/questions/195065/…
ALH
1

Con una proyección, puede lograr una situación en la que el conjunto de resultados proviene directamente del índice.

Si tiene un índice compuesto {x:1, y:1, z:1}donde ninguno de x, y, z es _id, debe proyectar {_id:0, x:1, y:1, z:1}porque _idsiempre se devuelve como parte del conjunto de resultados (cuando no se proyecta) y el motor necesita leer archivos de datos para obtenerlo. Esto se debe a que el índice no tiene el valor _id, solo apunta a ese documento donde se almacena el valor.

JJussi
fuente
Entonces, si elimino _idde la respuesta devuelta, ¿encaja eso en la RAM? ¿Eso ayuda?
ALH
1
MongoD (intenta) mantener al menos índices en la memoria (y la mayor cantidad de datos que quepa). Si su consulta se puede llenar directamente desde el índice y proyecta _id:0, el resultado se devuelve completamente desde la RAM, sin leer los datos del disco.
JJussi