276 votes

COUNT (*) vs. COUNT (1) vs COUNT (pk): quel est le meilleur?

Je trouve souvent ces trois variantes:

 SELECT COUNT(*) FROM Foo;
SELECT COUNT(1) FROM Foo;
SELECT COUNT(PrimaryKey) FROM Foo;
 

Autant que je sache, ils font tous la même chose, et je me retrouve à utiliser les trois dans mon code. Cependant, je n'aime pas faire la même chose de différentes manières. À qui dois-je coller? L'un d'entre eux est-il meilleur que les deux autres?

273voto

Michael Buen Points 20453

Utiliser * pour toutes vos requêtes que de compter tout, même pour les jointures, utilisez *

SELECT boss.boss_id, COUNT(subordinate.*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

Mais ne pas utiliser COUNT(*) pour la GAUCHE rejoint, qui va retourner 1, même si le subordonné de la table ne correspond pas à quelque chose de table parent

SELECT boss.boss_id, COUNT(*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

Ne vous laissez pas berner par ceux de conseiller lors de l'utilisation d' * dans le COMTE, elle récupère l'intégralité de la ligne à partir de votre table, en disant qu' * est lente. L' * sur SELECT COUNT(*) et SELECT * n'a aucun rapport les uns aux autres, ils sont tout à fait autre chose, ils ont juste partager un jeton, c'est à dire *. En fait, si il n'est pas permis de nommer un champ de même que le nom de la table, SGBDR langue concepteur pourrait donner des COUNT(tableNameHere) la même sémantique que l' COUNT(*). Exemple:

Pour compter les lignes, nous pourrions avoir ceci:

SELECT COUNT(emp) FROM emp

Et qu'ils pourraient le faire plus simple:

SELECT COUNT() FROM emp

Et pour la GAUCHE Rejoint, nous pourrions avoir ceci:

SELECT boss.boss_id, COUNT(subordinate)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

Mais ils ne peuvent pas le faire (COUNT(tableNameHere)) depuis la norme SQL permet de nommer un champ avec le même nom que son nom de la table:

CREATE TABLE fruit -- ORM-friendly name
(
fruit_id int NOT NULL,
fruit varchar(50), /* same name as table name, 
                and let's say, someone forgot to put NOT NULL */
shape varchar(50) NOT NULL,
color varchar(50) NOT NULL
)

Et aussi, il n'est pas une bonne pratique pour faire un champ nullable, disons que vous avez les valeurs de 'Banane', 'Pomme', NULL, 'Poires' sur les fruits de terrain. Ceci ne sera pas considéré tous les fruits, il ne cèdent 3, pas 4

SELECT count(fruit) FROM fruit

Bien que certains SGBDR faire ce genre de principe(pour compter les lignes du tableau, il accepte un nom de table comme le COMTE de paramètre), cela fonctionne dans Postgresql (si il n'y a pas d' subordinate champ dans les deux tableaux ci-dessous, c'est à dire tant qu'il n'y a pas de conflit de nom entre le champ nom et le nom de la table):

SELECT boss.boss_id, COUNT(subordinate)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

Mais qui pourrait causer de la confusion plus tard si nous allons ajouter un subordinate champ dans la table, comme il compte le champ(ce qui pourrait être nullable), pas les lignes de la table.

Donc, pour être sur le côté sécuritaire, utilisez:

SELECT boss.boss_id, COUNT(subordinate.*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

[MODIFIER]

En particulier COUNT(1), c'est un one-trick pony, il ne fonctionne bien que sur une table de requête:

SELECT COUNT(1) FROM tbl

Mais lorsque vous utilisez des jointures, cette astuce ne fonctionne pas sur les multi-requêtes de table sans sa sémantique se confondre, et, en particulier, vous ne pouvez pas écrire:

-- count the subordinates that belongs to boss
SELECT boss.boss_id, COUNT(subordinate.1)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

Alors, quel est le sens de COMPTAGE(1) ici?

SELECT boss.boss_id, COUNT(1)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

C'est ce que...?

-- counting all the subordinates only
SELECT boss.boss_id, COUNT(subordinate.boss_id)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

Ou ce que...?

-- or is that COUNT(1) will also count 1 for boss regardless if boss has a subordinate
SELECT boss.boss_id, COUNT(*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

Bien qu'il n'est pas difficile d'en déduire (même si certains pourraient être confondus) COUNT(1) est le même que COUNT(*) quel que soit le type de jointure. Mais pour la GAUCHE Rejoint conséquent, nous ne pouvons moule COUNT(1) de travail: COUNT(subordinate.boss_id), COUNT(subordinate.*)

Utilisez donc de la façon suivante:

-- count the subordinates that belongs to boss
SELECT boss.boss_id, COUNT(subordinate.boss_id)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

Fonctionne sur Postgresql, il est clair que vous voulez compter de la cardinalité de l'ensemble

-- count the subordinates that belongs to boss
SELECT boss.boss_id, COUNT(subordinate.*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

Une autre façon de calculer la cardinalité de l'ensemble, très similaire à l'anglais (il suffit de ne pas faire une colonne avec un nom de même que le nom de la table) : http://www.sqlfiddle.com/#!1/98515/7

select boss.boss_name, count(subordinate)
from boss
left join subordinate on subordinate.boss_code = boss.boss_code
group by boss.boss_name

Vous ne pouvez pas faire ceci: http://www.sqlfiddle.com/#!1/98515/8

select boss.boss_name, count(subordinate.1)
from boss
left join subordinate on subordinate.boss_code = boss.boss_code
group by boss.boss_name

Vous pouvez le faire, mais cela produit des résultats incorrects: http://www.sqlfiddle.com/#!1/98515/9

select boss.boss_name, count(1)
from boss
left join subordinate on subordinate.boss_code = boss.boss_code
group by boss.boss_name

Bas De Ligne

Utiliser COUNT(field) ou COUNT(*), et le bâton avec elle constamment, et si votre base de données permet de COUNT(tableHere) ou COUNT(tableHere.*), utilisez-le. En bref, ne pas utiliser COUNT(1) pour rien

63voto

Jonathan Leffler Points 299946

Deux d'entre eux produisent toujours la même réponse:

  • COUNT(*) compte le nombre de lignes
  • COUNT(1) compte le nombre de lignes

En supposant que le 'pk' est une clé primaire et que pas de les valeurs null sont autorisées dans les valeurs, puis

  • COUNT(pk) compte le nombre de lignes

Cependant, si 'pk' n'est pas contraint d'être pas null, il produit une réponse différente:

  • COUNT(possibly_null) compte le nombre de lignes avec des valeurs non null dans la colonne possibly_null.

  • COUNT(DISTINCT pk) compte le nombre de lignes (parce qu'une clé primaire ne permet pas de doublons).

  • COUNT(DISTINCT possibly_null_or_dup) compte le nombre de différentes valeurs non null dans la colonne possibly_null_or_dup.

  • COUNT(DISTINCT possibly_duplicated) compte le nombre de distinct (nécessairement non nulle) les valeurs dans la colonne possibly_duplicated quand les qui a la clause not NULL.

Normalement, j'écris COUNT(*); il est l'original recommandé de notation pour les SQL. De la même façon, avec la clause EXISTS, j'ai l'habitude d'écrire WHERE EXISTS(SELECT * FROM ...) parce que c'était à l'origine de recommander la notation. Il devrait y avoir aucun avantage à les alternatives; l'optimiseur doit voir à travers les plus obscurs de notations.

9voto

Jarod Elliott Points 7124

Cela dépendra du type de base de données que vous utilisez ainsi que du type de table dans certains cas.

Par exemple, en utilisant MySQL, count(*) sera rapide sous une table MyISAM mais ralentira sous InnoDB. Sous InnoDB, vous devez utiliser count(1) ou count(pk) .

9voto

gbn Points 197263

Demandé et répondu avant...

Livres sur la ligne dit "COUNT ( { [ [ ALL | DISTINCT ] expression ] | * } )"

"1" est un non-nulle expression c'est donc le même que COUNT(*). L'optimiseur de le reconnaît comme trivial , le même plan. Une clé primaire est unique et non-nulle (dans SQL Server au moins) alors COUNT(PK) = COUNT(*)

C'est un mythe à l' EXISTS (SELECT * ... ou EXISTS (SELECT 1 ...

Et de voir l' ANSI 92 spec, la section 6.5, les Règles Générales, le cas 1

        a) If COUNT(*) is specified, then the result is the cardinality
          of T.

        b) Otherwise, let TX be the single-column table that is the
          result of applying the <value expression> to each row of T
          and eliminating null values. If one or more null values are
          eliminated, then a completion condition is raised: warning-
          null value eliminated in set function.

7voto

Mitch Wheat Points 169614

COUNT(*) et COUNT(1) sont en fait différents (bien qu'ils fassent la même chose)

COUNT(*) est la cardinalité de la table (c'est-à-dire le nombre de lignes) et COUNT(exp) est le décompte des occurrences non NULL de l'expression, qui se trouve être une constante dans ce cas .

Je préfère COUNT(*)

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