63 votes

MongoDB 'count()' est très lent. Comment pouvons-nous l'améliorer ou le contourner ?

J'utilise actuellement MongoDB avec des millions d'enregistrements de données. J'ai découvert une chose qui est assez ennuyeuse.

Lorsque j'utilise la fonction 'count()' avec un petit nombre de collections de données interrogées, c'est très rapide. Cependant, lorsque la collection de données interrogée contient des milliers ou même des millions d'enregistrements de données, le système entier devient très lent.

Je me suis assuré que j'ai indexé les champs obligatoires.

Quelqu'un a-t-il rencontré une situation identique ? Comment faites-vous pour améliorer la situation ?

33voto

Andrew Orsich Points 24503

Il existe maintenant une autre optimisation que la création d'un index approprié.

db.users.ensureIndex({name:1});
db.users.find({name:"Andrei"}).count();

Si vous avez besoin de certains compteurs, je vous suggère de les précalculer quand c'est possible. En utilisant des compteurs atomiques $inc et ne pas utiliser count({}) du tout.

Mais les gars de mongodb travaillent dur sur mongodb, donc, count({}) améliorations prévues dans mongodb 2.1 selon jira bogue .

10voto

kamaradclimber Points 1337

Vous pouvez vous assurer que l'index est réellement utilisé sans aucun accès au disque.

Disons que vous voulez compter les enregistrements avec le nom : "Andrei".

Vous assurez l'indexation sur le nom (comme vous l'avez fait) et

db.users.find({name:"andrei"}, {_id:0, name:1}).count()

vous pouvez vérifier qu'il s'agit de la façon la plus rapide de compter (sauf avec le précalcul) en vérifiant si

db.users.find({name:"andrei"}, {_id:0, name:1}).explain() 

affiche un champ index_only défini sur true.

Cette astuce garantit que votre requête ne récupérera les enregistrements que dans la mémoire vive (index) et non sur le disque.

7voto

Vaclav Kohout Points 301

Pour moi, la solution a été de changer l'index en éparses . Cela dépend de la situation spécifique, mais faites un essai si vous le pouvez.

db.Account.createIndex( { "date_checked_1": 1 }, { sparse: true } )

db.Account.find({    
     "dateChecked" : { $exists : true }    
}).count()

318 milliers d'enregistrements dans la collection

  • 0.31 sec - avec un index clairsemé
  • 0.79 sec - avec un index non épars

7voto

Travis R Points 8935

Vous n'avez pas de chance pour l'instant, le comptage dans mongodb est horrible et ne s'améliorera pas dans un avenir proche. Voir : https://jira.mongodb.org/browse/SERVER-1752

Par expérience, vous ne devriez pratiquement jamais l'utiliser, sauf s'il s'agit d'une opération ponctuelle, d'un événement qui se produit très rarement, ou si votre base de données est assez petite.

Comme l'a dit @Andrew Orsich, utilisez des compteurs chaque fois que c'est possible (l'inconvénient des compteurs est le verrou d'écriture global, mais c'est quand même mieux que count()).

3voto

KushalSeth Points 828

J'ajoute mes observations basées sur la dernière version de mongodb 4.4. J'ai 0.80 TB taille de la collection.

J'ai créé un index ( UserObject.CountryID ) pour ma collection. et j'ai lancé cette requête.

db.users.aggregate([
{
    $match : {
        "UserObject.CountryID" : 3
    }
}]).group({_id: "Count", count: {$sum: 1}})

Il a fallu un total

  • 06800 ms pour récupérer le compte d'environ 13 millions (1,3 crore) d'enregistrements à rechercher 0.80 TB taille de la collection.
  • 16274 ms pour récupérer le compte d'environ 35 millions (3,5 crore) d'enregistrements à rechercher 0.80 TB taille de la collection.
  • 41615 ms pour aller chercher le compte d'environ 42 millions (4,2 crore) d'enregistrements de recherche 0.80 TB taille de la collection.

enter image description here

enter image description here

enter image description here

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X