Estoy tratando de mejorar el rendimiento de la siguiente 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
Actualmente con mis datos de prueba, me lleva aproximadamente un minuto. Tengo una cantidad limitada de información sobre los cambios en todo el procedimiento almacenado donde reside esta consulta, pero probablemente pueda hacer que modifiquen esta consulta. O agregue un índice. Intenté agregar el siguiente índice:
CREATE CLUSTERED INDEX ix_test ON #TempTable(AgentID, RuleId, GroupId, Passed)
Y en realidad duplicó la cantidad de tiempo que lleva la consulta. Obtengo el mismo efecto con un índice NO AGRUPADO.
Traté de reescribirlo de la siguiente manera sin efecto.
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
Luego intenté usar una función de ventanas como esta.
UPDATE [#TempTable]
SET Received = COUNT(DISTINCT (CASE WHEN Passed=1 THEN GroupId ELSE NULL END))
OVER (PARTITION BY AgentId, RuleId)
FROM [#TempTable]
En este punto comencé a recibir el error
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near 'distinct'.
Entonces tengo dos preguntas. Primero, ¿no puede hacer un COUNT DISTINCT con la cláusula OVER o simplemente lo escribí incorrectamente? Y segundo, ¿alguien puede sugerir una mejora que no haya probado? Para su información, esta es una instancia de SQL Server 2008 R2 Enterprise.
EDITAR: Aquí hay un enlace al plan de ejecución original. También debo tener en cuenta que mi gran problema es que esta consulta se ejecuta 30-50 veces.
https://onedrive.live.com/redir?resid=4C359AF42063BD98%21772
EDIT2: Aquí está el ciclo completo en el que se encuentra la declaración según lo solicitado en los comentarios. Estoy consultando con la persona que trabaja con esto de forma regular en cuanto al propósito del bucle.
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
fuente
count
si la columna fuera anulable. Si contiene nulos, debe restar 1.