Tout le monde sait que, dans les tables qui utilisent InnoDB comme moteur, les requêtes comme SELECT COUNT(*) FROM mytable
sont très inexactes et très lentes, surtout lorsque la table s'agrandit et qu'il y a des insertions / suppressions de lignes constantes pendant l'exécution de cette requête.
Si je comprends bien, InnoDB ne stocke pas le nombre de lignes dans une variable interne, ce qui est la raison de ce problème.
Ma question est: pourquoi en est-il ainsi? Serait-il si difficile de stocker de telles informations? C'est une information importante à connaître dans tant de situations. La seule difficulté que je vois si un tel décompte interne serait implémenté est lorsque des transactions sont impliquées: si la transaction n'est pas validée, comptez-vous les lignes insérées par elle ou non?
PS: je ne suis pas un expert des bases de données, je suis juste quelqu'un qui a MySQL comme simple hobby. Donc, si je viens de demander quelque chose de stupide, ne soyez pas excessivement critique: D.
SELECT COUNT(*) FROM ...
requêtes réelles sont précises. Si vous préférez, phpMyAdmin peut être configuré pour toujours utiliser le nombre exact de lignes au détriment de la vitesse. Plus d'infos: stackoverflow.com/questions/11926259/…Réponses:
Je suis d'accord avec @RemusRusanu (+1 pour sa réponse)
SELECT COUNT(*) FROM mydb.mytable
dans InnoDB se comporte comme un moteur de stockage transactionnel. Comparez-le à MyISAM.MyISAM
S'il
mydb.mytable
s'agit d'une table MyISAM, le lancementSELECT COUNT(*) FROM mydb.mytable;
revient à exécuterSELECT table_rows FROM information_schema.table WHERE table_schema = 'mydb' AND table_name = 'mytable';
. Cela déclenche une recherche rapide du nombre de lignes dans l'en-tête de la table MyISAM.InnoDB
S'il
mydb.mytable
s'agit d'une table InnoDB, vous obtenez un méli-mélo de choses qui se passent. Vous avez MVCC en cours, régissant les éléments suivants:Demander InnoDB pour un comptage de table nécessite une navigation à travers ces choses inquiétantes. En fait, on ne sait jamais vraiment si l'on
SELECT COUNT(*) from mydb.mytable
compte uniquement les lectures répétables ou si l'on inclut les lectures qui ont été validées et celles qui ne sont pas validées.Vous pouvez essayer de stabiliser un peu les choses en activant innodb_stats_on_metadata .
Selon la documentation MySQL sur innodb_stats_on_meta_data
La désactiver peut vous donner ou non un compte plus stable en termes de configuration de plans EXPLAIN. Il peut affecter les performances de
SELECT COUNT(*) from mydb.mytable
manière positive, négative ou pas du tout. Essayez et voyez !!!la source
Pour le démarreur, le «nombre actuel» n'existe pas à stocker dans une variable. Une requête comme
SELECT COUNT(*) FROM ...
est soumise au niveau d'isolement actuel et à toutes les transactions simultanées en attente. Selon le niveau d'isolement, la requête peut voir ou non les lignes insérées ou supprimées par les transactions non validées en attente. La seule façon de répondre est de compter les lignes visibles par la transaction en cours.Notez que je n'ai même pas abordé le sujet encore plus épineux des transactions simultanées qui commencent ou se terminent pendant le décompte. Sans parler des rollbacks ...
la source
COUNT(*)
requêtes sont rarement nécessaires dans la réalité et sont généralement le résultat de l'inexpérience des développeurs (comptez les lignes avant de les sélectionner!) Ou de la mauvaise conception de l'application.SELECT COUNT(*)
, ajoutez un non optimiséWHERE
à la table et vous aurez quelques utilisateurs mettant la base de données à genoux pour plusieurs compteurs de statistiques utiles.Bien qu'il soit théoriquement possible de conserver un décompte précis du nombre de lignes pour une table donnée avec InnoDB, cela se ferait au prix d'un grand nombre de verrouillages, ce qui affecterait négativement les performances. Il différerait également en fonction du niveau d'isolement.
MyISAM fait déjà le verrouillage au niveau de la table, donc pas de frais supplémentaires.
J'ai rarement besoin d'un nombre de lignes pour une table, bien que j'utilise assez COUNT (*). J'ai généralement une clause WHERE attachée. En utilisant un index efficace sur un petit ensemble de résultats, je trouve qu'ils sont assez rapides.
Je ne suis pas d'accord que les chiffres sont inexacts. Les chiffres représentent un instantané des données, et je les ai toujours trouvées exactes.
En bref, MySQL vous laisse le soin de l'implémenter pour InnoDB. Vous pouvez stocker un nombre et l'incrémenter / décrémenter après chaque requête. Cependant, la solution la plus simple est probablement de passer à MyISAM.
la source