Eu sempre li quando era preciso verificar a existência de uma linha sempre deve ser feita com EXISTS, em vez de com COUNT.
No entanto, em vários cenários recentes, medi uma melhoria de desempenho ao usar count.
O padrão é assim:
LEFT JOIN (
SELECT
someID
, COUNT(*)
FROM someTable
GROUP BY someID
) AS Alias ON (
Alias.someID = mainTable.ID
)
Eu não estou familiarizado com os métodos para saber o que está acontecendo "dentro" do SQL Server, então eu queria saber se havia uma falha não anunciada com EXISTS que dava perfeitamente sentido às medidas que eu fiz (EXISTS podem ser RBAR ?!).
Você tem alguma explicação para esse fenômeno?
EDITAR:
Aqui está um script completo que você pode executar:
SET NOCOUNT ON
SET STATISTICS IO OFF
DECLARE @tmp1 TABLE (
ID INT UNIQUE
)
DECLARE @tmp2 TABLE (
ID INT
, X INT IDENTITY
, UNIQUE (ID, X)
)
; WITH T(n) AS (
SELECT
ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master.dbo.spt_values AS S
)
, tally(n) AS (
SELECT
T2.n * 100 + T1.n
FROM T AS T1
CROSS JOIN T AS T2
WHERE T1.n <= 100
AND T2.n <= 100
)
INSERT @tmp1
SELECT n
FROM tally AS T1
WHERE n < 10000
; WITH T(n) AS (
SELECT
ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master.dbo.spt_values AS S
)
, tally(n) AS (
SELECT
T2.n * 100 + T1.n
FROM T AS T1
CROSS JOIN T AS T2
WHERE T1.n <= 100
AND T2.n <= 100
)
INSERT @tmp2
SELECT T1.n
FROM tally AS T1
CROSS JOIN T AS T2
WHERE T1.n < 10000
AND T1.n % 3 <> 0
AND T2.n < 1 + T1.n % 15
PRINT '
COUNT Version:
'
WAITFOR DELAY '00:00:01'
SET STATISTICS IO ON
SET STATISTICS TIME ON
SELECT
T1.ID
, CASE WHEN n > 0 THEN 1 ELSE 0 END AS DoesExist
FROM @tmp1 AS T1
LEFT JOIN (
SELECT
T2.ID
, COUNT(*) AS n
FROM @tmp2 AS T2
GROUP BY T2.ID
) AS T2 ON (
T2.ID = T1.ID
)
WHERE T1.ID BETWEEN 5000 AND 7000
OPTION (RECOMPILE) -- Required since table are filled within the same scope
SET STATISTICS TIME OFF
PRINT '
EXISTS Version:'
WAITFOR DELAY '00:00:01'
SET STATISTICS TIME ON
SELECT
T1.ID
, CASE WHEN EXISTS (
SELECT 1
FROM @tmp2 AS T2
WHERE T2.ID = T1.ID
) THEN 1 ELSE 0 END AS DoesExist
FROM @tmp1 AS T1
WHERE T1.ID BETWEEN 5000 AND 7000
OPTION (RECOMPILE) -- Required since table are filled within the same scope
SET STATISTICS TIME OFF
No SQL Server 2008R2 (Seven 64bits), recebo este resultado
COUNT
Versão:
Tabela '# 455F344D'. Contagem de varredura 1, leituras lógicas 8, leituras físicas 0, leituras de leitura antecipada 0, leituras lógicas de lob 0, leituras físicas de lob 0, leituras físicas de lob 0, leituras de leitura antecipada de 0.
Tabela '# 492FC531'. Contagem de varredura 1, leituras lógicas 30, 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 = 81 ms.
EXISTS
Versão:
Tabela '# 492FC531'. Contagem de varredura 1, leituras lógicas 96, leituras físicas 0, leituras de leitura antecipada 0, leituras lógicas de lob 0, leituras físicas de lob 0, leituras de leitura antecipada de
lobes lê 0. Tabela '# 455F344D'. Contagem de varredura 1, leituras lógicas 8, leituras físicas 0, leituras antecipadas 0, 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 = 0 ms, tempo decorrido = 76 ms.