ejemplos sql sql-server performance

ejemplos - Count(*) vs Count(1)-SQL Server



sql server count rows (11)

Solo me pregunto si alguno de ustedes usa Count(1) over Count(*) y si hay una diferencia notable en el rendimiento o si esto es solo un hábito heredado que se ha logrado desde los días pasados.

(La base de datos específica es SQL Server 2005 ).


A medida que esta pregunta surge una y otra vez, aquí hay una respuesta más. Espero agregar algo para principiantes que se preguntan acerca de las "mejores prácticas" aquí.

SELECT COUNT(*) FROM something cuenta registros que es una tarea fácil.

SELECT COUNT(1) FROM something recupera un 1 por registro y luego cuenta los 1 que no son nulos, lo que esencialmente es contar los registros, solo que es más complicado.

Dicho esto: Un buen dbms advierte que la segunda declaración resultará en el mismo conteo que la primera declaración y la volverá a interpretar en consecuencia, para no hacer un trabajo innecesario. Por lo general, ambas declaraciones resultarán en el mismo plan de ejecución y tomarán la misma cantidad de tiempo.

Sin embargo, desde el punto de la legibilidad, debe utilizar la primera declaración. Usted quiere contar los registros, así que cuente los registros, no las expresiones. Use COUNT (expresión) solo cuando quiera contar ocurrencias no nulas de algo.


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 debido a un error del optimizador. Dado que ambos formularios se utilizan con mucha frecuencia en las consultas, no tendría sentido que un DBMS permitiera que dicho error permaneciera sin arreglar. Por lo tanto, encontrará que el rendimiento de ambos formularios es (probablemente) idéntico en todos los DBMS de SQL principales.


Ejecuté una prueba rápida en SQL Server 2012 en una caja de hyper-v RAM de 8 GB. Puedes ver los resultados por ti mismo. No estaba ejecutando ninguna otra aplicación de ventana aparte de SQL Server Management Studio mientras ejecutaba estas pruebas.

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 registros 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 puede atribuirse 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 carreras y hago un promedio. Si para un conjunto de datos tan grande, la diferencia llega a menos de 100 milisegundos, entonces podemos concluir fácilmente que las dos consultas no muestran ninguna diferencia de rendimiento en el motor de SQL Server.

Nota : la memoria RAM alcanza casi el 100% de uso en ambas ejecuciones. Reinicié el servicio de SQL Server antes de iniciar ambas ejecuciones.


En SQL Server, estas declaraciones producen los mismos planes.

Contrariamente a la opinión popular, en Oracle también lo hacen.

SYS_GUID() en Oracle es una función intensiva en computación.

En mi base de datos de prueba, 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 función necesita evaluar cada SYS_GUID() devuelto para asegurarse de que no sea un NULL .

Sin embargo, esta consulta:

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

corre por 2 segundos, ya que ni siquiera intenta evaluar SYS_GUID() (a pesar de que * es un argumento para COUNT(*) )


En el estándar SQL-92, COUNT(*) significa específicamente "la cardinalidad de la expresión de la tabla" (podría ser una tabla base, `VIEW, 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 referencia a ninguna columna ( COUNT(''a'') donde a es un literal y COUNT(a) donde a es una columna puede producir resultados diferentes).

En la misma línea, COUNT(*) puede ser fácilmente seleccionado por un codificador humano familiarizado con los Estándares SQL, una habilidad útil cuando se trabaja con más de un proveedor de SQL.

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

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


Espero que el optimizador se asegure de que no haya una diferencia real fuera de los casos de borde extraño.

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

Dicho esto, siempre he usado COUNT(*) .


Fácil de demostrar COUNT (*) vs COUNT (<algunos 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


Hay un article que muestra que COUNT(1) en Oracle es solo un alias de COUNT(*) , con una prueba al respecto.

Citaré algunas partes:

Hay una parte del software de la base de datos que se llama "El optimizador", que se define en la documentación oficial como "Software de base de datos integrado que determina la forma más eficiente de ejecutar una declaración SQL".

Uno de los componentes del optimizador se llama "el transformador", cuya función es determinar si es ventajoso reescribir la declaración SQL original en una declaración SQL semánticamente equivalente que podría ser más eficiente.

¿Le gustaría ver qué hace el optimizador cuando escribe una consulta usando COUNT (1)?

Con un usuario con el privilegio ALTER SESSION , puede colocar un tracefile_identifier , habilitar el rastreo del optimizador y ejecutar la selección de COUNT(1) , como: SELECT /* test-1 */ COUNT(1) FROM employees; .

Después de eso, necesita localizar los archivos de rastreo, lo que se puede hacer con SELECT VALUE FROM V$DIAG_INFO WHERE NAME = ''Diag Trace''; . Más adelante en el archivo, encontrará:

SELECT COUNT(*) “COUNT(1)” FROM “COURSE”.”EMPLOYEES” “EMPLOYEES”

Como puedes ver, es solo un alias para COUNT(*) .

Otro comentario importante: el COUNT(*) fue realmente más rápido hace dos décadas en Oracle, antes de Oracle 7.3:

Count (1) se ha reescrito en count (*) desde la versión 7.3 porque a Oracle le gusta la sintonización automática de declaraciones míticas. En Oracle7 anterior, oracle tenía que evaluar (1) para cada fila, como una función, antes de que existiera DETERMINISTIC y NON-DETERMINISTIC.

Así que hace dos décadas, el conde (*) era más rápido.

Para otras bases de datos como Sql Server, debe investigarse individualmente para cada una.

Sé que esta pregunta es específica para el Servidor SQL, pero las otras preguntas sobre SO sobre el mismo tema, sin mencionar la base de datos, se cerraron y se marcaron como duplicadas en esta respuesta.


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 igual 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.

Editar, Ago 2011

Pregunta similar en DBA.SE.

Edición, Diciembre 2011

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

Caso:

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

Es decir, el estándar ANSI lo reconoce como un 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 sería evaluado según ANSI

b) De lo contrario, deje que TX sea la tabla de una sola columna que es el resultado de aplicar la <expresión de valor> 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-


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


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, tiempo 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, tiempo transcurrido = 37 ms.

He ejecutado esto cientos de veces, borrando el caché cada vez ... Los resultados varían de vez en cuando a medida que varía la carga del servidor, pero casi siempre el conteo (*) tiene un mayor tiempo de CPU.