72 votes

Dois-je COUNT(*) ou non ?

Je sais que c'est généralement une mauvaise idée de faire des requêtes de ce genre :

SELECT * FROM `group_relations`

Mais si je ne veux que le compte, dois-je opter pour cette requête qui permet de modifier la table tout en obtenant les mêmes résultats ?

SELECT COUNT(*) FROM `group_relations`

Ou le plus spécifique

SELECT COUNT(`group_id`) FROM `group_relations`

J'ai le sentiment que cette dernière pourrait potentiellement être plus rapide, mais y a-t-il d'autres éléments à prendre en compte ?

Mise à jour : J'utilise InnoDB dans ce cas, désolé de ne pas avoir été plus précis.

101voto

pilif Points 7172

Si la colonne en question est NOT NULL, vos deux requêtes sont équivalentes. Lorsque group_id contient des valeurs nulles,

select count(*)

comptera toutes les lignes, tandis que

select count(group_id)

ne comptera que les lignes où group_id n'est pas nul.

En outre, certains systèmes de bases de données, comme MySQL, utilisent une optimisation lorsque vous demandez count(*), ce qui rend ces requêtes un peu plus rapides que la requête spécifique.

Personnellement, lorsque je ne fais que compter, je fais count(*) pour être en sécurité avec les nulles.

22voto

Sebastian Dietz Points 4309

Si je me souviens bien, en MYSQL COUNT(*) compte toutes les lignes, alors que COUNT(nom_colonne) compte seulement les lignes qui ont une valeur non NULL dans la colonne donnée.

11voto

Eran Galperin Points 49594

COUNT(*) compte toutes les lignes tandis que COUNT(nom_colonne) comptera seulement les lignes sans valeurs NULL dans la colonne spécifiée.

Important à noter dans MySQL :

COUNT() est très rapide sur les tables MyISAM pour les colonnes * ou non nulles, puisque le nombre de lignes est mis en cache. InnoDB n'a pas de cache pour le nombre de lignes, donc il n'y a pas de différence de performance pour COUNT(*) ou COUNT(nom_colonne), que la colonne soit nulle ou non. Vous pouvez en savoir plus sur les différences sur ce poste sur le blog consacré aux performances de MySQL.

8voto

Sergio Points 5161

Si vous essayez SELECT COUNT(1) FROM group_relations, il sera un peu plus rapide car il n'essaiera pas de récupérer les informations de vos colonnes.

Edit : Je viens de faire quelques recherches et j'ai découvert que cela n'arrive que dans certaines bases de données. Dans sqlserver c'est pareil d'utiliser 1 ou *, mais sur oracle c'est plus rapide d'utiliser 1.

http://social.msdn.microsoft.com/forums/en-US/transactsql/thread/9367c580-087a-4fc1-bf88-91a51a4ee018/

Apparemment il n'y a pas de différence entre eux dans mysql, comme sqlserver le parser semble changer la requête en select(1). Désolé si je vous ai induit en erreur d'une manière ou d'une autre.

5voto

Chris Points 227

J'étais moi-même curieux à ce sujet. C'est très bien de lire de la documentation et des réponses théoriques, mais j'aime les équilibrer avec des preuves empiriques.

J'ai une table MySQL (InnoDB) qui contient 5 607 997 enregistrements. Cette table se trouve dans mon propre bac à sable privé, je sais donc que son contenu est statique et que personne d'autre n'utilise le serveur. Je pense que cela élimine efficacement tous les effets extérieurs sur les performances. J'ai une table avec un champ de clé primaire à incrémentation automatique (Id) dont je sais qu'il ne sera jamais nul et que j'utiliserai pour mon test de clause where (WHERE Id IS NOT NULL).

Le seul autre problème possible que je vois lors des tests est le cache. La première fois qu'une requête est exécutée sera toujours plus lente que les requêtes suivantes qui utilisent les mêmes index. C'est ce que j'appellerai ci-dessous l'appel à l'ensemencement du cache. Pour varier un peu, je l'ai exécutée avec une clause where dont je sais qu'elle sera toujours évaluée comme vraie, quelles que soient les données (TRUE = TRUE).

Cela dit, voici mes résultats :

Type de requête

      |  w/o WHERE          | where id is not null |  where true=true

COUNT()

      |  9 min 30.13 sec ++ | 6 min 16.68 sec ++   | 2 min 21.80 sec ++
      |  6 min 13.34 sec    | 1 min 36.02 sec      | 2 min 0.11 sec 
      |  6 min 10.06 se     | 1 min 33.47 sec      | 1 min 50.54 sec

COUNT(Id)

      |  5 min 59.87 sec    | 1 min 34.47 sec      | 2 min 3.96 sec 
      |  5 min 44.95 sec    | 1 min 13.09 sec      | 2 min 6.48 sec

COUNT(1)

      | 6 min 49.64 sec    | 2 min 0.80 sec       | 2 min 11.64 sec
      | 6 min 31.64 sec    | 1 min 41.19 sec      | 1 min 43.51 sec

++Ceci est considéré comme l'appel du cache-sexe. On s'attend à ce qu'il soit plus lent que les autres.

Je dirais que les résultats parlent d'eux-mêmes. COUNT(Id) l'emporte généralement sur les autres. L'ajout d'une clause Where réduit considérablement le temps d'accès, même s'il s'agit d'une clause dont vous savez qu'elle sera évaluée comme vraie. Le point idéal semble être COUNT(Id)... WHERE Id IS NOT NULL.

J'aimerais bien voir les résultats d'autres personnes, peut-être avec des tableaux plus petits ou avec des clauses where sur des champs différents de celui que vous comptez. Je suis sûr qu'il existe d'autres variations que je n'ai pas prises en compte.

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