Estou tentando melhorar o desempenho da seguinte consulta:
UPDATE [#TempTable]
SET Received = r.Number
FROM [#TempTable]
INNER JOIN (SELECT AgentID,
RuleID,
COUNT(DISTINCT (GroupId)) Number
FROM [#TempTable]
WHERE Passed = 1
GROUP BY AgentID,
RuleID
) r ON r.RuleID = [#TempTable].RuleID AND
r.AgentID = [#TempTable].AgentID
Atualmente, com meus dados de teste, leva cerca de um minuto. Eu tenho uma quantidade limitada de entrada para alterações no procedimento armazenado em geral em que essa consulta reside, mas provavelmente posso fazê-las modificar essa consulta. Ou adicione um índice. Tentei adicionar o seguinte índice:
CREATE CLUSTERED INDEX ix_test ON #TempTable(AgentID, RuleId, GroupId, Passed)
E na verdade dobrou a quantidade de tempo que a consulta leva. Eu obtenho o mesmo efeito com um índice NÃO CLUSTERED.
Tentei reescrevê-lo da seguinte maneira, sem nenhum efeito.
WITH r AS (SELECT AgentID,
RuleID,
COUNT(DISTINCT (GroupId)) Number
FROM [#TempTable]
WHERE Passed = 1
GROUP BY AgentID,
RuleID
)
UPDATE [#TempTable]
SET Received = r.Number
FROM [#TempTable]
INNER JOIN r
ON r.RuleID = [#TempTable].RuleID AND
r.AgentID = [#TempTable].AgentID
Em seguida, tentei usar uma função de janelas como esta.
UPDATE [#TempTable]
SET Received = COUNT(DISTINCT (CASE WHEN Passed=1 THEN GroupId ELSE NULL END))
OVER (PARTITION BY AgentId, RuleId)
FROM [#TempTable]
Nesse ponto, comecei a receber o erro
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near 'distinct'.
Então, eu tenho duas perguntas. Primeiro, você não pode executar um COUNT DISTINCT com a cláusula OVER ou acabei de escrevê-lo incorretamente? E segundo, alguém pode sugerir uma melhoria que eu ainda não tentei? Para sua informação, esta é uma instância do SQL Server 2008 R2 Enterprise.
EDIT: Aqui está um link para o plano de execução original. Também devo observar que meu grande problema é que essa consulta está sendo executada 30 a 50 vezes.
https://onedrive.live.com/redir?resid=4C359AF42063BD98%21772
EDIT2: Aqui está o loop completo em que a declaração está, conforme solicitado nos comentários. Estou checando com a pessoa que trabalha com isso regularmente quanto ao objetivo do loop.
DECLARE @Counting INT
SELECT @Counting = 1
-- BEGIN: Cascading Rule check --
WHILE @Counting <= 30
BEGIN
UPDATE w1
SET Passed = 1
FROM [#TempTable] w1,
[#TempTable] w3
WHERE w3.AgentID = w1.AgentID AND
w3.RuleID = w1.CascadeRuleID AND
w3.RulePassed = 1 AND
w1.Passed = 0 AND
w1.NotFlag = 0
UPDATE w1
SET Passed = 1
FROM [#TempTable] w1,
[#TempTable] w3
WHERE w3.AgentID = w1.AgentID AND
w3.RuleID = w1.CascadeRuleID AND
w3.RulePassed = 0 AND
w1.Passed = 0 AND
w1.NotFlag = 1
UPDATE [#TempTable]
SET Received = r.Number
FROM [#TempTable]
INNER JOIN (SELECT AgentID,
RuleID,
COUNT(DISTINCT (GroupID)) Number
FROM [#TempTable]
WHERE Passed = 1
GROUP BY AgentID,
RuleID
) r ON r.RuleID = [#TempTable].RuleID AND
r.AgentID = [#TempTable].AgentID
UPDATE [#TempTable]
SET RulePassed = 1
WHERE TotalNeeded = Received
SELECT @Counting = @Counting + 1
END
fonte
count
se a coluna fosse anulável. Se ele contiver algum valor nulo, você precisará subtrair 1.