COUNT(*) frente a COUNT(1) frente a COUNT(pk): ¿cuál es mejor? [duplicar]
A menudo encuentro estas tres variantes:
SELECT COUNT(*) FROM Foo;
SELECT COUNT(1) FROM Foo;
SELECT COUNT(PrimaryKey) FROM Foo;
Hasta donde puedo ver, todos hacen lo mismo y me encuentro usando los tres en mi código base. Sin embargo, no me gusta hacer lo mismo de diferentes maneras. ¿A cuál debería apegarme? ¿Alguno de ellos es mejor que los otros dos?
Línea de fondo
Utilice COUNT(field)
o COUNT(*)
y manténgalo de forma constante, y si su base de datos lo permite COUNT(tableHere)
, COUNT(tableHere.*)
utilícelo.
En resumen, no lo uses COUNT(1)
para nada. Es un pony de un solo truco, que rara vez hace lo que quieres, y en esos casos raros equivale acount(*)
Usar count(*)
para contar
Úselo *
para todas sus consultas que necesiten contar todo, incluso para uniones, use*
SELECT boss.boss_id, COUNT(subordinate.*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
Pero no lo use COUNT(*)
para uniones IZQUIERDA, ya que devolverá 1 incluso si la tabla subordinada no coincide con nada de la tabla principal.
SELECT boss.boss_id, COUNT(*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
No se deje engañar por aquellos que le advierten que cuando se usa *
en COUNT, recupera la fila completa de su tabla, diciendo que *
es lento. On *
y no tienen relación SELECT COUNT(*)
entre SELECT *
sí, son cosas completamente diferentes, solo comparten un token común, es decir *
.
Una sintaxis alternativa
De hecho, si no está permitido nombrar un campo con el mismo nombre que el nombre de su tabla, el diseñador del lenguaje RDBMS podría proporcionar COUNT(tableNameHere)
la misma semántica que COUNT(*)
. Ejemplo:
Para contar filas podríamos tener esto:
SELECT COUNT(emp) FROM emp
Y podrían hacerlo más sencillo:
SELECT COUNT() FROM emp
Y para LEFT JOIN, podríamos tener esto:
SELECT boss.boss_id, COUNT(subordinate)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
Pero no pueden hacer eso ( COUNT(tableNameHere)
) ya que el estándar SQL permite nombrar un campo con el mismo nombre que el nombre de su tabla:
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
)
Contando con nulo
Además, no es una buena práctica convertir un campo en anulable si su nombre coincide con el nombre de la tabla. Supongamos que tiene los valores 'Banana', 'Apple', NULL, 'Pears' en el fruit
campo. Esto no contará todas las filas, solo producirá 3, no 4
SELECT count(fruit) FROM fruit
Aunque algunos RDBMS siguen ese tipo de principio (para contar las filas de la tabla, aceptan el nombre de la tabla como parámetro de COUNT), esto funcionará en Postgresql (si no hay ningún subordinate
campo en ninguna de las dos tablas siguientes, es decir, siempre que no haya conflicto de nombre entre el nombre del campo y el nombre de la tabla):
SELECT boss.boss_id, COUNT(subordinate)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
Pero eso podría causar confusión más adelante si agregamos un subordinate
campo en la tabla, ya que contará el campo (que podría aceptar valores NULL), no las filas de la tabla.
Entonces, para estar seguro, use:
SELECT boss.boss_id, COUNT(subordinate.*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
count(1)
: El pony de un solo truco
En particular COUNT(1)
, es un pony de un solo truco , funciona bien solo en una consulta de tabla:
SELECT COUNT(1) FROM tbl
Pero cuando usas combinaciones, ese truco no funcionará en consultas de varias tablas sin que su semántica se confunda y, en particular, no puedes escribir:
-- 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
Entonces, ¿cuál es el significado de COUNT(1) aquí?
SELECT boss.boss_id, COUNT(1)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
¿Es esto...?
-- 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
O esto...?
-- 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
Si lo piensa detenidamente, puede inferir que COUNT(1)
es lo mismo que COUNT(*)
, independientemente del tipo de unión. Pero para obtener el resultado LEFT JOIN, no podemos moldearlo COUNT(1)
para que funcione como COUNT(subordinate.boss_id)
:COUNT(subordinate.*)
Entonces simplemente use cualquiera de los siguientes:
-- 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
Funciona en Postgresql, está claro que quieres contar la cardinalidad del conjunto.
-- 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
Otra forma de contar la cardinalidad del conjunto, muy parecida a la inglesa (simplemente no haga una columna con el mismo nombre que el nombre de la tabla): 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
No puedes hacer esto: 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
Puede hacer esto, pero produce un resultado incorrecto: 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
Dos de ellos siempre producen la misma respuesta:
COUNT(*)
cuenta el número de filasCOUNT(1)
también cuenta el número de filas
Suponiendo que pk
es una clave principal y que no se permiten valores nulos en los valores, entonces
COUNT(pk)
también cuenta el número de filas
Sin embargo, si pk
no está obligado a ser no nulo, se produce una respuesta diferente:
COUNT(possibly_null)
cuenta el número de filas con valores no nulos en la columnapossibly_null
.COUNT(DISTINCT pk)
también cuenta el número de filas (porque una clave primaria no permite duplicados).COUNT(DISTINCT possibly_null_or_dup)
cuenta el número de valores distintos no nulos en la columnapossibly_null_or_dup
.COUNT(DISTINCT possibly_duplicated)
cuenta el número de valores distintos (necesariamente no nulos) en la columnapossibly_duplicated
cuando tiene laNOT NULL
cláusula.
Normalmente escribo COUNT(*)
; es la notación original recomendada para SQL. De manera similar, con la EXISTS
cláusula, normalmente escribo WHERE EXISTS(SELECT * FROM ...)
porque esa era la notación recomendada original. Las alternativas no deberían generar ningún beneficio; el optimizador debería ver a través de las notaciones más oscuras.
Preguntado y respondido antes...
Libros en línea dice " COUNT ( { [ [ ALL | DISTINCT ] expression ] | * } )
"
"1" es una expresión no nula, por lo que es lo mismo que COUNT(*)
. El optimizador lo reconoce como trivial y ofrece el mismo plan. Una PK es única y no nula (al menos en SQL Server), por lo que COUNT(PK)
= COUNT(*)
Este es un mito similar EXISTS (SELECT * ...
oEXISTS (SELECT 1 ...
Y consulte la especificación ANSI 92 , sección 6.5, Reglas generales, caso 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.
Siento que las características de rendimiento cambian de un DBMS a otro. Todo depende de cómo elijan implementarlo. Como he trabajado extensamente en Oracle, lo contaré desde esa perspectiva.
COUNT(*)
- Obtiene la fila completa en el conjunto de resultados antes de pasar a la función de conteo; la función de conteo agregará 1 si la fila no es nula
COUNT(1)
- No recuperará ninguna fila; en su lugar, se llama al recuento con un valor constante de 1 para cada fila de la tabla cuando coincide WHERE
.
COUNT(PK)
- La PK en Oracle está indexada. Esto significa que Oracle tiene que leer sólo el índice. Normalmente, una fila en el árbol del índice B+ es muchas veces más pequeña que la fila real. Entonces, considerando la tasa de IOPS del disco, Oracle puede recuperar muchas veces más filas del índice con una sola transferencia en bloque en comparación con una fila completa. Esto conduce a un mayor rendimiento de la consulta.
A partir de esto puede ver que el primer recuento es el más lento y el último recuento es el más rápido en Oracle.