2011-10-05 3 views
46

J'utilise actuellement MongoDB avec des millions de données. J'ai découvert une chose qui est assez ennuyante.MongoDB 'count()' est très lent. Comment pouvons-nous améliorer/travailler avec?

Lorsque j'utilise la fonction 'count()' avec un petit nombre de données interrogées, c'est très rapide. Cependant, lorsque la collection de données interrogées contient des milliers, voire des millions d'enregistrements de données, l'ensemble du système devient très lent.

J'ai vérifié que j'avais indexé les champs obligatoires.

Est-ce que quelqu'un a rencontré une chose identique? Comment faites-vous pour améliorer cela?

Répondre

25

Il existe maintenant une autre optimisation que de créer un index approprié.

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

Si vous avez besoin de compteurs, je suggère de les calculer à chaque fois que cela est possible. En utilisant l'opération $inc atomique et ne pas utiliser count({}) du tout.

Mais mongodb les gars qui travaillent dur sur mongodb, donc, count({}) améliorations qu'ils prévoient dans mongodb 2.1 selon jira bug.

+0

merci pour la réponse. Cependant, disons que je voudrais filtrer les enregistrements de données et compter le numéro d'enregistrement. Dans ce cas, $ inc ne m'aide pas beaucoup, n'est-ce pas? –

+0

@WinstonChen: Cela dépend de votre filtre. Fournir un exemple je vais répondre. –

+1

Merci. Disons que j'ai des millions d'enregistrements comme celui-ci: {_ id: "hash_code_here", nom du livre: "Les quatre étapes de l'épiphanie", auteur: "Steven-Gary-Blank", catégorie: 10}. J'ai 1 million de livres ou alors dont la catégorie est 10, et la même que la catégorie 9, 8, 7, etc. J'ai une page avec une fonction de pagination qui filtre et montre à mes visiteurs tous les livres de catégorie 10 ou 9, ou 8, ou 7 .... La catégorie est censée être l'un des critères du filtre. Les visiteurs peuvent également ajouter des critères «auteur» ou d'autres critères. Comment pourrais-je l'implémenter avec $ inc? –

10

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

Disons que vous voulez compter les enregistrements avec le nom: « Andrei »

Vous assurez index 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 est le plus rapide façon de compter (sauf avec pré-calcul) en vérifiant si

affiche un champ index_only défini sur true.

Cette astuce fera en sorte que votre requête récupérera des enregistrements uniquement à partir de ram (index) et non à partir du disque.

+0

Si MongoDB décide qu'il ne devrait pas faire index_only pour une opération comme count, par défaut, cela ressemble beaucoup à un bug. – kizzx2

+0

c'était vrai en 2011, peut-être que cela a changé avec https://jira.mongodb.org/browse/SERVER-1752 – kamaradclimber

3

Vous n'avez pas vraiment de chance pour le moment, count in mongodb est affreux et ne s'améliorera pas dans un futur proche. Voir: https://jira.mongodb.org/browse/SERVER-1752

Par expérience, vous ne devriez pratiquement jamais l'utiliser à moins que ce soit une chose ponctuelle, quelque chose qui se produit très rarement, ou votre base de données est assez petite. Comme l'a déclaré @Andrew Orsich, utiliser les compteurs autant que possible (la chute aux compteurs est le verrou global en écriture, mais mieux que count()).

3

Pour moi, la solution était l'indice de changement à clairsemé. Cela dépend de la situation spécifique, essayez-le si vous le pouvez.

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

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

318 milliers enregistrements collection

  • 0,31 sec - avec l'indice clairsemés
  • 0.79 sec - avec indice non clairsemé