Na sua pergunta, você detalha alguns testes que preparou onde "prova" que a opção de adição é mais rápida do que comparar as colunas discretas. Eu suspeito que sua metodologia de teste pode ter falhas de várias maneiras, como @gbn e @srutzky mencionaram.
Primeiro, você precisa garantir que não está testando o SQL Server Management Studio (ou qualquer outro cliente que esteja usando). Por exemplo, se você estiver executando um SELECT *
de uma tabela com 3 milhões de linhas, estará testando principalmente a capacidade do SSMS de extrair linhas do SQL Server e renderizá-las na tela. É muito melhor usar algo como o SELECT COUNT(1)
que nega a necessidade de puxar milhões de linhas pela rede e renderizá-las na tela.
Segundo, você precisa estar ciente do cache de dados do SQL Server. Normalmente, testamos a velocidade de leitura de dados do armazenamento e do processamento desses dados, a partir de um cache frio (por exemplo, os buffers do SQL Server estão vazios). Ocasionalmente, faz sentido fazer todos os seus testes com um cache quente, mas você precisa abordá-los explicitamente com isso em mente.
Para um teste de cache frio, você precisa executar CHECKPOINT
e DBCC DROPCLEANBUFFERS
antes de cada execução do teste.
Para o teste que você perguntou na sua pergunta, criei o seguinte banco de testes:
IF COALESCE(OBJECT_ID('tempdb..#SomeTest'), 0) <> 0
BEGIN
DROP TABLE #SomeTest;
END
CREATE TABLE #SomeTest
(
TestID INT NOT NULL
PRIMARY KEY
IDENTITY(1,1)
, A INT NOT NULL
, B FLOAT NOT NULL
, C MONEY NOT NULL
, D BIGINT NOT NULL
);
INSERT INTO #SomeTest (A, B, C, D)
SELECT o1.object_id, o2.object_id, o3.object_id, o4.object_id
FROM sys.objects o1
, sys.objects o2
, sys.objects o3
, sys.objects o4;
SELECT COUNT(1)
FROM #SomeTest;
Isso retorna uma contagem de 260.144.641 na minha máquina.
Para testar o método "adição", eu corro:
CHECKPOINT 5;
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;
SET STATISTICS IO, TIME ON;
GO
SELECT COUNT(1)
FROM #SomeTest st
WHERE (st.A + st.B + st.C + st.D) = 0;
GO
SET STATISTICS IO, TIME OFF;
A guia de mensagens mostra:
Tabela '#SomeTest'. Contagem de varredura 3, leituras lógicas 1322661, leituras físicas 0, leituras antecipadas 1313877, leituras lógicas lob 0, leituras lógicas lob 0, leituras físicas lob 0, leituras antecipadas lob.
Tempos de execução do SQL Server: tempo de CPU = 49047 ms, tempo decorrido = 173451 ms.
Para o teste "colunas discretas":
CHECKPOINT 5;
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;
SET STATISTICS IO, TIME ON;
GO
SELECT COUNT(1)
FROM #SomeTest st
WHERE st.A = 0
AND st.B = 0
AND st.C = 0
AND st.D = 0;
GO
SET STATISTICS IO, TIME OFF;
novamente, na guia Mensagens:
Tabela '#SomeTest'. Contagem de varredura 3, leituras lógicas 1322661, leituras físicas 0, leituras de leitura antecipada 1322661, leituras lógicas de lob 0, leituras físicas de lob 0, leituras físicas de lob 0, leituras de leitura antecipada 0.
Tempos de execução do SQL Server: tempo de CPU = 8938 ms, tempo decorrido = 162581 ms.
Nas estatísticas acima, você pode ver a segunda variante, com as colunas discretas comparadas com 0, o tempo decorrido é cerca de 10 segundos mais curto e o tempo da CPU é cerca de 6 vezes menor. As longas durações nos meus testes acima são principalmente o resultado da leitura de muitas linhas do disco. Se você reduzir o número de linhas para 3 milhões, verá que as proporções permanecem as mesmas, mas os tempos decorridos caem visivelmente, pois a E / S do disco tem muito menos efeito.
Com o método "Adição":
Tabela '#SomeTest'. Contagem de varredura 3, leituras lógicas 15255, leituras físicas 0, leituras de read-ahead 0, leituras lógicas de lob 0, leituras físicas de lob 0, leituras físicas de lob 0, leituras de read-ahead de lob 0.
Tempos de execução do SQL Server: tempo de CPU = 499 ms, tempo decorrido = 256 ms.
Com o método "colunas discretas":
Tabela '#SomeTest'. Contagem de varredura 3, leituras lógicas 15255, leituras físicas 0, leituras de read-ahead 0, leituras lógicas de lob 0, leituras físicas de lob 0, leituras físicas de lob 0, leituras de read-ahead de lob 0.
Tempos de execução do SQL Server: tempo de CPU = 94 ms, tempo decorrido = 53 ms.
O que fará uma diferença realmente grande para este teste? Um índice apropriado, como:
CREATE INDEX IX_SomeTest ON #SomeTest(A, B, C, D);
O método "adição":
Tabela '#SomeTest'. Contagem de varredura 3, leituras lógicas 14235, leituras físicas 0, leituras de read-ahead 0, leituras lógicas de lob 0, leituras físicas de lob 0, leituras físicas de lob 0, leituras de read-ahead de lob 0.
Tempos de execução do SQL Server: tempo de CPU = 546 ms, tempo decorrido = 314 ms.
O método "colunas discretas":
Tabela '#SomeTest'. Contagem de varreduras 1, leituras lógicas 3, leituras físicas 0, leituras de read-ahead 0, leituras lógicas de lob 0, leituras físicas de lob 0, leituras físicas de lob 0, leituras de read-ahead de lob 0.
Tempos de execução do SQL Server: tempo de CPU = 0 ms, tempo decorrido = 0 ms.
O plano de execução para cada consulta (com o índice acima no local) é bastante revelador.
O método "adição", que deve executar uma verificação de todo o índice:
e o método "colunas discretas", que pode procurar a primeira linha do índice em que a coluna principal do índice A
é zero: