Recuento (*) vs Conteo (1)

Me pregunto si alguno de ustedes utiliza el Count(1) sobre el Count(*) y si hay una diferencia notable en el performance o si este es solo un hábito henetworkingado que se ha presentado desde times pasados.

(La database específica es SQL Server 2005.)

No hay diferencia.

Razón:

Los libros en línea dicen " COUNT ( { [ [ ALL | DISTINCT ] expression ] | * } ) "

"1" es una expresión no nula: por lo tanto, es lo mismo que COUNT(*) . El optimizador lo reconoce por lo que es: trivial.

Lo mismo que EXISTS (SELECT * ... o EXISTS (SELECT 1 ...

Ejemplo:

 SELECT COUNT(1) FROM dbo.tab800krows SELECT COUNT(1),FKID FROM dbo.tab800krows GROUP BY FKID SELECT COUNT(*) FROM dbo.tab800krows SELECT COUNT(*),FKID FROM dbo.tab800krows GROUP BY FKID 

Mismo IO, mismo plan, las obras

Edit, ago 2011

Pregunta similar en DBA.SE.

Editar, dic 2011

COUNT(*) se menciona específicamente en ANSI-92 (busque " Scalar expressions 125 ")

Caso:

a) Si se especifica COUNT (*), entonces el resultado es la cardinalidad de T.

Es decir, el estándar ANSI lo reconoce como sangrado obvio a lo que se refiere. COUNT(1) ha sido optimizado por los proveedores de RDBMS debido a esta superstición. De lo contrario, se evaluaría según ANSI

b) De lo contrario, deje que TX sea la tabla de columna única que es el resultado de aplicar la <value expression> a cada fila de T y eliminar los valores nulos. Si se eliminan uno o más valores nulos, se genera una condición de finalización: advertencia-

En SQL Server, estas declaraciones producen los mismos planes.

Al contrario de la opinión popular, en Oracle también lo hacen.

SYS_GUID() en Oracle es una function bastante computacional.

En mi database de testing, t_even es una tabla con 1,000,000 filas

Esta consulta:

 SELECT COUNT(SYS_GUID()) FROM t_even 

se ejecuta durante 48 segundos, ya que la function necesita evaluar cada SYS_GUID() devuelto para asegurarse de que no sea NULL .

Sin embargo, esta consulta:

 SELECT COUNT(*) FROM ( SELECT SYS_GUID() FROM t_even ) 

se ejecuta por más de 2 segundos, ya que ni siquiera trata de evaluar SYS_GUID() (a pesar de * ser argumento para COUNT(*) )

Claramente, COUNT (*) y COUNT (1) siempre devolverán el mismo resultado. Por lo tanto, si uno fuera más lento que el otro, sería efectivamente debido a un error del optimizador. Como ambos formularios se utilizan con mucha frecuencia en las consultas, no tendría sentido que un DBMS permitiera que dicho error permanezca sin corregir. Por lo tanto, encontrará que el performance de ambas forms es (probablemente) idéntico en todos los principales DBMS de SQL.

En el estándar SQL-92, COUNT(*) significa específicamente "la cardinalidad de la expresión de tabla" (podría ser una tabla base, `VER, tabla derivada, CTE, etc.).

Supongo que la idea era que COUNT(*) es fácil de analizar. El uso de cualquier otra expresión requiere que el analizador se asegure de que no haga reference a ninguna columna ( COUNT('a') donde a es un literal y COUNT(a) donde a es una columna puede arrojar resultados diferentes).

En el mismo sentido, COUNT(*) puede ser elegido fácilmente por un codificador humano familiarizado con los Estándares SQL, una habilidad útil cuando se trabaja con más de una oferta de SQL de un proveedor.

Además, en el caso especial SELECT COUNT(*) FROM MyPersistedTable; , el pensamiento es que el DBMS es probable que contenga statistics para la cardinalidad de la tabla.

Por lo tanto, dado que COUNT(1) y COUNT(*) son semánticamente equivalentes, uso COUNT(*) .

COUNT(*) y COUNT(1) son iguales en caso de resultado y performance.

Esperaría que el optimizador se asegure de que no haya diferencia real fuera de los casos de bordes extraños.

Como con cualquier cosa, la única forma real de decir es medir sus casos específicos.

Dicho esto, siempre he usado COUNT(*) .

 SET STATISTICS TIME ON select count(1) from MyTable (nolock) -- table containing 1 million records. 

Tiempos de ejecución de SQL Server:
Tiempo de CPU = 31 ms, time transcurrido = 36 ms.

 select count(*) from MyTable (nolock) -- table containing 1 million records. 

Tiempos de ejecución de SQL Server:
Tiempo de CPU = 46 ms, time transcurrido = 37 ms.

Lo he ejecutado cientos de veces, borrando el caching cada vez .. Los resultados varían de vez en cuando ya que la carga del server varía, pero casi siempre count (*) tiene un time de CPU más alto.

Como esta pregunta surge una y otra vez, aquí hay una respuesta más. Espero agregar algo para principiantes preguntándome acerca de las "mejores prácticas" aquí.

SELECT COUNT(*) FROM something count loggings, que es una tarea fácil.

SELECT COUNT(1) FROM something recupera un 1 por logging y que count los 1s que no son nulos, que es esencialmente loggings de conteo, solo que más complicado.

Habiendo dicho esto: Good dbms nota que la segunda statement dará como resultado la misma count que la primera y la reinterpretará en consecuencia, para no hacer un trabajo innecesario. Por lo general, ambas declaraciones darán como resultado el mismo plan de ejecución y tomarán la misma cantidad de time.

Sin embargo, desde el punto de lectura, debe usar la primera statement. Desea contar los loggings, así que cuente los loggings, no las expresiones. Use COUNT (expresión) solo cuando desee contar las ocurrencias no nulas de algo.

Ejecuté una testing rápida en SQL Server 2012 en un cuadro hiperv de RAM de 8 GB. Puedes ver los resultados por ti mismo. No estaba ejecutando ninguna otra aplicación de window aparte de SQL Server Management Studio mientras ejecutaba estas testings.

Mi esquema de tabla:

 CREATE TABLE [dbo].[employee]( [Id] [bigint] IDENTITY(1,1) NOT NULL, [Name] [nvarchar](50) NOT NULL, CONSTRAINT [PK_employee] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO 

Número total de loggings en la tabla de Employee : 178090131 (~ 178 millones de filas)

Primera consulta:

 Set Statistics Time On Go Select Count(*) From Employee Go Set Statistics Time Off Go 

Resultado de la primera consulta:

  SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 35 ms. (1 row(s) affected) SQL Server Execution Times: CPU time = 10766 ms, elapsed time = 70265 ms. SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 0 ms. 

Segunda consulta:

  Set Statistics Time On Go Select Count(1) From Employee Go Set Statistics Time Off Go 

Resultado de la segunda consulta:

  SQL Server parse and compile time: CPU time = 14 ms, elapsed time = 14 ms. (1 row(s) affected) SQL Server Execution Times: CPU time = 11031 ms, elapsed time = 70182 ms. SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 0 ms. 

Puede observar que hay una diferencia de 83 (= 70265 – 70182) milisegundos que se puede atribuir fácilmente a la condición exacta del sistema en el momento en que se ejecutan las consultas. También hice una sola carrera, por lo que esta diferencia será más precisa si hago varias ejecuciones y hago algún promedio. Si para un set de datos tan grande la diferencia llega a less de 100 milisegundos, entonces podemos concluir fácilmente que las dos consultas no tienen ninguna diferencia de performance exhibida por el Motor SQL Server.

Nota : La RAM alcanza casi el 100% de uso en ambas carreras. Reinicié el service de SQL Server antes de iniciar ambas ejecuciones.

Fácil de demostrar COUNT (*) vs COUNT (<some col>) –

 USE tempdb; GO IF OBJECT_ID( N'dbo.Blitzen', N'U') IS NOT NULL DROP TABLE dbo.Blitzen; GO CREATE TABLE dbo.Blitzen (ID INT NULL, Somelala CHAR(1) NULL); INSERT dbo.Blitzen SELECT 1, 'A'; INSERT dbo.Blitzen SELECT NULL, NULL; INSERT dbo.Blitzen SELECT NULL, 'A'; INSERT dbo.Blitzen SELECT 1, NULL; SELECT COUNT(*), COUNT(1), COUNT(ID), COUNT(Somelala) FROM dbo.Blitzen; GO DROP TABLE dbo.Blitzen; GO