Eu queria saber qual das duas abordagens a seguir é mais rápida:
1) Três COUNT
:
SELECT Approved = (SELECT COUNT(*) FROM dbo.Claims d
WHERE d.Status = 'Approved'),
Valid = (SELECT COUNT(*) FROM dbo.Claims d
WHERE d.Status = 'Valid'),
Reject = (SELECT COUNT(*) FROM dbo.Claims d
WHERE d.Status = 'Reject')
2) SUM
com FROM
-cláusula:
SELECT Approved = SUM(CASE WHEN Status = 'Approved' THEN 1 ELSE 0 END),
Valid = SUM(CASE WHEN Status = 'Valid' THEN 1 ELSE 0 END),
Reject = SUM(CASE WHEN Status = 'Reject' THEN 1 ELSE 0 END)
FROM dbo.Claims c;
Fiquei surpreso que a diferença é tão grande. A primeira consulta com três subconsultas retorna o resultado imediatamente, enquanto a segunda SUM
abordagem precisa de 18 segundos.
Claims
é uma exibição que seleciona de uma tabela contendo ~ 18 milhões de linhas. Há um índice na coluna FK da ClaimStatus
tabela que contém o nome do status.
Por que faz uma diferença tão grande se eu uso COUNT
ou SUM
?
Planos de execução:
Existem 12 status no total. Esses três status pertencem a 7% de todas as linhas.
Esta é a visão real, não tenho certeza se é relevante:
CREATE VIEW [dbo].[Claims]
AS
SELECT
mu.Marketunitname AS MarketUnit,
c.Countryname AS Country,
gsp.Gspname AS GSP,
gsp.Wcmskeynumber AS GspNumber,
sl.Slname AS SL,
sl.Wcmskeynumber AS SlNumber,
m.Modelname AS Model,
m.Salesname AS [Model-Salesname],
s.Claimstatusname AS [Status],
d.Work_order AS [Work Order],
d.Ssn_number AS IMEI,
d.Ssn_out,
Remarks,
d.Claimnumber AS [Claim-Number],
d.Rma_number AS [RMA-Number],
dbo.ToShortDateString(d.Received_Date, 1) AS [Received Date],
Iddata,
Fisl,
Fimodel,
Ficlaimstatus
FROM Tabdata AS d
INNER JOIN Locsl AS sl
ON d.Fisl = sl.Idsl
INNER JOIN Locgsp AS gsp
ON sl.Figsp = gsp.Idgsp
INNER JOIN Loccountry AS c
ON gsp.Ficountry = c.Idcountry
INNER JOIN Locmarketunit AS mu
ON c.Fimarketunit = mu.Idmarketunit
INNER JOIN Modmodel AS m
ON d.Fimodel = m.Idmodel
INNER JOIN Dimclaimstatus AS s
ON d.Ficlaimstatus = s.Idclaimstatus
INNER JOIN Tdefproducttype
ON d.Fiproducttype = Tdefproducttype.Idproducttype
LEFT OUTER JOIN Tdefservicelevel
ON d.Fimaxservicelevel = Tdefservicelevel.Idservicelevel
LEFT OUTER JOIN Tdefactioncode AS ac
ON d.Fimaxactioncode = ac.Idactioncode
sql-server
performance
sql-server-2005
t-sql
Tim Schmelter
fonte
fonte
COUNT
versão do plano. Você pode editar o gosto naSUM
versão para apontar para o plano correto?Authorized
.WHERE c.Status = 'Approved' or c.Status = 'Valid' or c.status = 'Reject'
àSUM
variante.Respostas:
A
COUNT(*)
versão pode simplesmente procurar o índice que você possui na coluna de status uma vez para cada status selecionado, enquanto aSUM(...)
versão precisa buscar o índice doze vezes (o número total de tipos de status exclusivos).Claramente, procurar um índice três vezes será mais rápido do que procurá-lo 12 vezes.
O primeiro plano requer uma concessão de memória de 238MB, enquanto o segundo plano requer uma concessão de memória de 650MB. Ele pode ser que a concessão de memória maior não poderia ser imediatamente preenchido, tornando a consulta que muito mais lento.
Altere a segunda consulta para ser:
Isso permitirá que o otimizador de consultas elimine 75% da procura do índice e deve resultar em uma concessão de memória necessária mais baixa, em requisitos de E / S mais baixos e no tempo de resultado mais rápido.
A
SUM(CASE WHEN ...)
construção essencialmente impede que o otimizador de consulta envie osStatus
predicados para baixo na parte de busca de índice do plano.fonte
max server memory
opção - ela deve ser configurada com o valor correto para o seu sistema. Você pode examinar esta pergunta e as respostas para obter detalhes sobre como fazer isso.