Contagem (*) vs Contagem (1) – SQL Server

Basta saber se algum de vocês usa o Count(1) em Count(*) e se há uma diferença notável no desempenho ou se esse é apenas um hábito herdado que foi antecipado de dias passados?

(O database específico é o SQL Server 2005 )

Não há diferença.

Razão:

Livros on-line diz ” COUNT ( { [ [ ALL | DISTINCT ] expression ] | * } )

“1” é uma expressão não nula: portanto, é igual a COUNT(*) . O otimizador reconhece o que é: trivial.

O mesmo que EXISTS (SELECT * ... ou EXISTS (SELECT 1 ...

Exemplo:

 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 

Mesmo IO, mesmo plano, as obras

Edit, ago 2011

Pergunta semelhante sobre DBA.SE.

Edit, dez 2011

COUNT(*) é mencionado especificamente em ANSI-92 (procure por ” Scalar expressions 125 “)

Caso:

a) Se COUNT (*) for especificado, o resultado é a cardinalidade de T.

Ou seja, o padrão ANSI reconhece como sangramento óbvio o que você quer dizer. COUNT(1) foi otimizado pelos fornecedores de RDBMS devido a essa superstição. Caso contrário, seria avaliado de acordo com ANSI

b) Caso contrário, deixe TX ser a tabela de coluna única que é o resultado da aplicação da a cada linha de T e da eliminação de valores nulos. Se um ou mais valores nulos forem eliminados, uma condição de conclusão será levantada: aviso

No SQL Server, essas instruções produzem os mesmos planos.

Ao contrário da opinião popular, no Oracle eles também.

SYS_GUID() no Oracle é bastante function de computação intensiva.

No meu database de teste, t_even é uma tabela com 1,000,000 linhas

Esta consulta:

 SELECT COUNT(SYS_GUID()) FROM t_even 

é executado por 48 segundos, pois a function precisa avaliar cada SYS_GUID() retornado para garantir que não seja NULL .

No entanto, esta consulta:

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

é executado por apenas 2 segundos, pois nem sequer tenta avaliar SYS_GUID() (apesar de * ser argumento para COUNT(*) )

Claramente, COUNT (*) e COUNT (1) sempre retornarão o mesmo resultado. Portanto, se um fosse mais lento que o outro, seria efetivamente devido a um erro do otimizador. Uma vez que ambos os formulários são usados ​​com muita frequência em consultas, não faria sentido para um DBMS permitir que tal erro permanecesse não corrigido. Portanto, você descobrirá que o desempenho de ambas as formas é (provavelmente) idêntico em todos os principais DBMSs SQL.

No padrão SQL-92, COUNT(*) significa especificamente “a cardinalidade da expressão da tabela” (pode ser uma tabela base, `VIEW, tabela derivada, CTE, etc).

Eu acho que a ideia era que COUNT(*) é fácil de analisar. Usar qualquer outra expressão requer o analisador para garantir que ele não faça referência a nenhuma coluna ( COUNT('a') que a é um literal e COUNT(a) que a é uma coluna pode gerar resultados diferentes).

Na mesma linha, COUNT(*) pode ser facilmente selecionado por um codificador humano familiarizado com os Padrões SQL, uma habilidade útil ao trabalhar com a oferta SQL de mais de um fornecedor.

Além disso, no caso especial SELECT COUNT(*) FROM MyPersistedTable; , o pensamento é o SGBD é susceptível de manter statistics para a cardinalidade da tabela.

Portanto, como COUNT(1) e COUNT(*) são semanticamente equivalentes, uso COUNT(*) .

COUNT(*) e COUNT(1) são iguais em caso de resultado e desempenho.

Eu esperaria que o otimizador garantisse que não houvesse diferença real fora dos casos de borda estranhos.

Como com qualquer coisa, a única maneira real de saber é medir seus casos específicos.

Dito isso, sempre usei COUNT(*) .

Fiz um teste rápido no SQL Server 2012 em uma checkbox hyper-v de 8 GB de RAM. Você pode ver os resultados por si mesmo. Eu não estava executando nenhum outro aplicativo em janelas além do SQL Server Management Studio durante a execução desses testes.

Meu esquema de tabela:

 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 na tabela Employee : 178090131 (~ 178 milhões de linhas)

Primeira consulta:

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

Resultado da primeira 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 da 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. 

Você pode notar que há uma diferença de 83 (= 70265 – 70182) milissegundos que podem ser facilmente atribuídos à condição exata do sistema no momento em que as consultas são executadas. Também fiz uma única corrida, então essa diferença se tornará mais precisa se eu fizer várias execuções e fizer alguma média. Se, para um dataset tão grande, a diferença estiver chegando a menos de 100 milissegundos, podemos concluir facilmente que as duas consultas não apresentam nenhuma diferença de desempenho exibida pelo Mecanismo do SQL Server.

Nota : RAM atinge perto de 100% de uso em ambas as execuções. Eu reiniciei o serviço do SQL Server antes de iniciar as duas execuções.

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

Tempos de Execução do SQL Server:
Tempo de CPU = 31 ms, tempo decorrido = 36 ms.

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

Tempos de Execução do SQL Server:
Tempo de CPU = 46 ms, tempo decorrido = 37 ms.

Eu corri isso centenas de vezes, limpando o cache toda vez. Os resultados variam de tempos em tempos, já que a carga do servidor varia, mas quase sempre count (*) tem um tempo de CPU mais alto.

Como esta questão surge de novo e de novo, aqui está mais uma resposta. Espero adicionar algo para iniciantes que estejam se perguntando sobre as “melhores práticas” aqui.

SELECT COUNT(*) FROM something conta registros que é uma tarefa fácil.

SELECT COUNT(1) FROM something recupera um 1 por registro e que conta os 1s que não são nulos, o que é essencialmente contar registros, apenas mais complicado.

Dito isto: Bons dbms notam que a segunda instrução resultará na mesma contagem que a primeira declaração e a reinterpretará de acordo, para não fazer um trabalho desnecessário. Então, normalmente, ambas as instruções resultarão no mesmo plano de execução e levarão o mesmo tempo.

No entanto, a partir do ponto de legibilidade, você deve usar a primeira instrução. Você deseja contar registros, portanto, contar registros, não expressões. Use COUNT (expressão) somente quando quiser contar ocorrências não nulas de algo.

Há um artigo mostrando que o COUNT(1) no Oracle é apenas um alias para COUNT(*) , com uma prova sobre isso.

Vou citar algumas partes:

Há uma parte do software de database que é chamada “O Otimizador”, que é definida na documentação oficial como “Software de database embutido que determina a maneira mais eficiente de executar uma instrução SQL”.

Um dos componentes do otimizador é chamado de “o transformador”, cuja function é determinar se é vantajoso rewrite a instrução SQL original em uma instrução SQL semanticamente equivalente que poderia ser mais eficiente.

Gostaria de ver o que o otimizador faz quando você escreve uma consulta usando COUNT (1)?

Com um usuário com privilégio ALTER SESSION , é possível colocar um tracefile_identifier , ativar o rastreio do otimizador e executar a opção COUNT(1) , como: SELECT /* test-1 */ COUNT(1) FROM employees; .

Depois disso, você precisa localizar os arquivos de rastreamento, o que pode ser feito com SELECT VALUE FROM V$DIAG_INFO WHERE NAME = 'Diag Trace'; . Mais tarde, o arquivo, você encontrará:

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

Como você pode ver, é apenas um alias para COUNT(*) .

Outro comentário importante: o COUNT(*) foi realmente mais rápido há duas décadas na Oracle, antes do Oracle 7.3:

A contagem (1) foi reescrita em count (*) desde 7.3 porque o Oracle gosta de Auto-ajustar instruções míticas. No Oracle7 anterior, o oracle tinha que avaliar (1) para cada linha, como uma function, antes que DETERMINISTIC e NON-DETERMINISTIC existissem.

Então, duas décadas atrás, count (*) era mais rápido

Para outros bancos de dados como o Sql Server, ele deve ser pesquisado individualmente para cada um.

Eu sei que essa questão é específica para o Sql Server, mas as outras perguntas sobre SO sobre o mesmo assunto, sem mencionar o database, foram fechadas e marcadas como duplicadas dessa resposta.

Fácil de demonstrar COUNT (*) vs COUNT () –

 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