2012-03-19 11 views
14
//FAST 
db.datasources.find().count() 
12036788 

//SLOW  
db.datasources.find({nid:19882}).count() 
10161684 

Índice de nidMongo recuento muy lento cuando hay millones de registros

alguna manera de hacer la segunda consulta más rápido? (Tarda aproximadamente 8 segundos)

+0

Aunque tenga un índice en nid, es posible que no sea residente en la memoria. ¿Qué sucede si ejecuta la consulta por segunda vez, es más rápido? –

+0

No, aún es lento –

+0

¿Cuánto tiempo tarda la primera consulta? ¿Estás seguro de que no hay otras operaciones ejecutándose en el servidor? –

Respuesta

23

Las consultas de recuento, indexadas o no, son lentas debido al hecho de que MongoDB todavía tiene que hacer una caminata completa por el árbol en b para encontrar la cantidad apropiada de documentos que coincidan con sus criterios. La razón de esto es que la estructura del árbol b de MongoDB no se "cuenta", lo que significa que cada nodo no almacena información sobre la cantidad de elementos en el nodo/subárbol.

El problema se informó aquí https://jira.mongodb.org/browse/SERVER-1752 y actualmente no hay ninguna solución para mejorar el rendimiento que no sea el mantenimiento manual de un contador para esa colección que, obviamente, viene con algunas desventajas.

También tenga en cuenta que la versión db.col.count() (por lo que no hay criterios) puede tomar un atajo grande y en realidad no realiza una consulta, por lo tanto, es la velocidad. Dicho esto, no siempre informa el mismo valor que una consulta de conteo que debería devolver todos los elementos (no estará en entornos fragmentados con alto rendimiento de escritura, por ejemplo). Hasta debate si es un error o no. Creo que es.

Tenga en cuenta que en 2.3+ se introdujo una optimización significativa que debería (y lo hace) mejorar el rendimiento de los recuentos en los campos indexados. Ver: https://jira.mongodb.org/browse/SERVER-7745

+2

Me pregunto cómo usar para examinar la paginación con mongodb, si el recuento es tan lento. – Oleg

+1

La paginación es un problema más complejo de lo que podría parecer cuando se trabaja con big data. Por ejemplo, omitir (N) es una operación o (N) por lo que no se puede hacer una paginación basada en omisión (pageIndex * pageSize) .limit (pageSize) ni se puede determinar el recuento total de páginas con un conteo(). Puede hacerlo, pero se volverá más lento a medida que aumente el tamaño de los datos, que es un mal patrón. Hay soluciones que te importan, son más complicadas que eso. Todo lo que dijo count() debería ser más rápido que ellos y MongoDB debería (al menos opcionalmente) usar b-trees contados en mi opinión. –

+2

No tuve suerte buscando la paginación en big data que no utiliza skip y limit. Si alguien tiene un ejemplo sería genial compartir – vodich

0

Tiene que mirar a través de cada campo de cada documento para el segundo. Puede indexar nid para acelerar el recuento.

+6

Tengo un índice en nid –

11

Como dijo @Remon, count() tiene que escanear todos los documentos que coinciden con la consulta/filtro. Es O (n) donde n es el número de documentos que coincidirá con el índice, o el número de documentos en la colección si el campo no está indexado.

En tales casos, normalmente desea volver a visitar su requisito. ¿Realmente necesita un número preciso para el resultado 10161684? Si la precisión es importante, debe mantener un contador separado para la consulta en particular.

Pero en la mayoría de los casos, la precisión no es importante. Es uno de los dos:

  • No te importa si se trata de 10 millones o 10,2 millones de dólares, pero el orden de magnitud es importante, es decir, se preocupa por si se trata de 8 millones o 10 millones.
  • Solo le importa el número exacto si es pequeño. Es decir, le interesa saber que hay 44 resultados o 72. Pero una vez que va más allá, digamos, 1000, puede decir 'Más de 1000 objetos' encontrados para el usuario.

En mis aplicaciones, encontré que la segunda opción es lo que quiero. Por lo tanto, también limito la consulta count(), de modo que el conteo se detiene cuando alcanza un límite. De este modo:

db.datasources.find({nid: 19882}).limit(1000).count(true) 

Para el usuario, exhibo '1000 o más resultados encontrados' si el recuento es de 1000, de lo contrario, puedo mostrar el número exacto.

En cuanto a la primera opción ... No he pensado en una solución ordenada todavía.

+0

¿Qué hace '.count (true)' aquí? – chovy

+1

count() devuelve la cantidad de documentos coincidentes. count() toma un argumento 'applySkipLimit' que afecta si el conteo está en el conjunto salteado y limitado, o el conjunto completo (solo filtrado). Si pasa la verdad, limitará el conteo a 1000. Si pasa el mensaje falso, revisará todos los documentos coincidentes para obtener el conteo; esto será lento y no lo que usted desea. – user3392439