Я пытаюсь улучшить производительность следующего запроса:
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
В настоящее время с моими тестовыми данными это занимает около минуты. У меня есть ограниченное количество входных данных для изменений всей хранимой процедуры, в которой находится этот запрос, но я, вероятно, могу заставить их изменить этот запрос. Или добавить индекс. Я попытался добавить следующий индекс:
CREATE CLUSTERED INDEX ix_test ON #TempTable(AgentID, RuleId, GroupId, Passed)
И это фактически удвоило количество времени, которое занимает запрос. Я получаю тот же эффект с некластеризованным индексом.
Я попытался переписать это следующим образом безрезультатно.
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
Затем я попытался использовать функцию управления окнами, как это.
UPDATE [#TempTable]
SET Received = COUNT(DISTINCT (CASE WHEN Passed=1 THEN GroupId ELSE NULL END))
OVER (PARTITION BY AgentId, RuleId)
FROM [#TempTable]
В этот момент я начал получать ошибку
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near 'distinct'.
Итак, у меня есть два вопроса. Во-первых, вы не можете сделать COUNT DISTINCT с предложением OVER или я просто написал это неправильно? И во-вторых, кто-нибудь может предложить улучшение, которое я еще не пробовал? К вашему сведению, это экземпляр SQL Server 2008 R2 Enterprise.
РЕДАКТИРОВАТЬ: Вот ссылка на оригинальный план выполнения. Я также должен отметить, что моя большая проблема в том, что этот запрос выполняется 30-50 раз.
https://onedrive.live.com/redir?resid=4C359AF42063BD98%21772
РЕДАКТИРОВАТЬ 2: Вот полный цикл, в котором оператор находится в соответствии с просьбой в комментариях. Я проверяю с человеком, который работает с этим на регулярной основе относительно цели цикла.
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
источник
count
если бы столбец обнулялся. Если он содержит какие-либо нули, вы должны вычесть 1.