El rendimiento de MongoDB en consultas de agregación

Después de escuchar tantas cosas buenas sobre el rendimiento de MongoDB, decidimos probar Mongodb para resolver un problema que tenemos. Empecé moviendo todos los registros que tenemos en varias bases de datos de MySQL a una única colección en mongodb. Esto dio como resultado una colección con 29 millones de documentos (cada uno de ellos tiene al menos 20 campos) que ocupa alrededor de 100 GB de espacio en HD. Decidimos ponerlos todos en una sola colección, ya que todos los documentos tienen la misma estructura y queremos consultar y agregar resultados en todos esos documentos.

Creé algunos índices para que coincidan con mis consultas, de lo contrario, incluso un simple conteo () tomaría años. Sin embargo, las consultas como distinct () y group () aún toman demasiado tiempo.

Ejemplo:

// creation of a compound index db.collection.ensureIndex({'metadata.system':1, 'metadata.company':1}) // query to get all the combinations companies and systems db.collection.group({key: { 'metadata.system':true, 'metadata.company':true }, reduce: function(obj,prev) {}, initial: {} }); 

Eché un vistazo al registro de mongod y tiene muchas líneas como estas (al ejecutar la consulta anterior):

 Thu Apr 8 14:40:05 getmore database.collection cid:973023491046432059 ntoreturn:0 query: {} bytes:1048890 nreturned:417 154ms Thu Apr 8 14:40:08 getmore database.collection cid:973023491046432059 ntoreturn:0 query: {} bytes:1050205 nreturned:414 430ms Thu Apr 8 14:40:18 getmore database.collection cid:973023491046432059 ntoreturn:0 query: {} bytes:1049748 nreturned:201 130ms Thu Apr 8 14:40:27 getmore database.collection cid:973023491046432059 ntoreturn:0 query: {} bytes:1051925 nreturned:221 118ms Thu Apr 8 14:40:30 getmore database.collection cid:973023491046432059 ntoreturn:0 query: {} bytes:1053096 nreturned:250 164ms ... Thu Apr 8 15:04:18 query database.$cmd ntoreturn:1 command reslen:4130 1475894ms 

Esta consulta tomó 1475894ms, que es mucho más larga de lo que esperaría (la lista de resultados tiene alrededor de 60 entradas). En primer lugar, ¿se espera esto dada la gran cantidad de documentos en mi colección? ¿Se espera que las consultas de agregación en general sean tan lentas en mongodb? ¿Alguna idea sobre cómo puedo mejorar el rendimiento?

Estoy ejecutando mongod en una sola máquina con un núcleo dual y 10 GB de memoria.

Gracias.

La idea es mejorar el rendimiento de las consultas de agregación utilizando MapReduce en una base de datos fragmentada que se distribuye en varias máquinas.

Hice algunas comparaciones del rendimiento de Mapreduce de Mongo con una statement grupal por selección en Oracle en la misma máquina. Encontré que Mongo era aproximadamente 25 veces más lento. Esto significa que tengo que fragmentar los datos en al menos 25 máquinas para obtener el mismo rendimiento con Mongo que Oracle entrega en una sola máquina. Usé una colección / tabla con aproximadamente 14 millones de documentos / filas.

Exportar los datos de mongo a través de mongoexport.exe y usar los datos exportados como una tabla externa en Oracle y hacer un group-by en Oracle fue mucho más rápido que usar el propio MapReduce de Mongo.

Un par de cosas.

1) Su consulta de grupo está procesando muchos datos. Si bien su conjunto de resultados es pequeño, parece que está haciendo una escala de tabla de todos los datos en su colección para generar ese pequeño resultado. Esta es probablemente la causa raíz de la lentitud. Para acelerar esto, es posible que desee ver el rendimiento del disco de su servidor a través de iostat mientras la consulta se está ejecutando, ya que es probable que sea el cuello de botella.

2) Como se ha señalado en otras respuestas, el comando de grupo usa el intérprete de JavaScript, que limitará el rendimiento. Puede intentar usar el nuevo marco de agregación que se publica como beta en 2.1 (nota: esta es una versión inestable desde el 24 de febrero de 2012). Ver http://blog.mongodb.org/post/16015854270/operations-in-the-new-aggregation-framework para una buena introducción. Esto no solucionará el problema del volumen de datos en (1), pero se implementa en C ++ y si el tiempo de JavaScript es el cuello de botella, entonces debería ser mucho más rápido.

3) Otro enfoque sería usar map-reduce incremental para generar una segunda colección con sus resultados agrupados. La idea es ejecutar un trabajo de reducción de mapa para agregar los resultados una vez, y luego ejecutar periódicamente otro trabajo de reducción de mapa que vuelva a reducir los datos nuevos en la colección existente. Luego puede consultar esta segunda colección desde su aplicación en lugar de ejecutar un comando grupal todo el tiempo.

La agregación (reducir mapa o no) es muy lenta en mongo porque la realiza la máquina virtual de JavaScript, no el motor de la base de datos. Esto sigue siendo una limitación de esto (muy bueno, imo) db para los datos de series de tiempo.