Usiłuję poprawić wydajność następującego zapytania:
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
Obecnie z moimi danymi testowymi zajmuje to około minuty. Mam ograniczoną ilość danych wejściowych do zmian w całej procedurze składowanej, w której znajduje się to zapytanie, ale prawdopodobnie mogę je zmusić do zmodyfikowania tego jednego zapytania. Lub dodaj indeks. Próbowałem dodać następujący indeks:
CREATE CLUSTERED INDEX ix_test ON #TempTable(AgentID, RuleId, GroupId, Passed)
I faktycznie podwoił czas potrzebny na zapytanie. Ten sam efekt uzyskuję dzięki indeksowi NON-CLUSTERED.
Próbowałem przepisać go w następujący sposób, bez efektu.
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
Następnie próbowałem użyć takiej funkcji okienkowania.
UPDATE [#TempTable]
SET Received = COUNT(DISTINCT (CASE WHEN Passed=1 THEN GroupId ELSE NULL END))
OVER (PARTITION BY AgentId, RuleId)
FROM [#TempTable]
W tym momencie zacząłem otrzymywać błąd
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near 'distinct'.
Mam więc dwa pytania. Po pierwsze, czy nie możesz wykonać ODLICZANIA LICZBY z klauzulą OVER, czy po prostu napisałem go niepoprawnie? Po drugie, czy ktoś może zasugerować ulepszenie, którego jeszcze nie próbowałem? Do Twojej dyspozycji jest instancja SQL Server 2008 R2 Enterprise.
EDYCJA: Oto link do oryginalnego planu wykonania. Powinienem również zauważyć, że moim wielkim problemem jest to, że to zapytanie jest uruchamiane 30-50 razy.
https://onedrive.live.com/redir?resid=4C359AF42063BD98%21772
EDYCJA 2: Oto pełna pętla, w której znajduje się instrukcja, zgodnie z żądaniem w komentarzach. Sprawdzam z osobą, która pracuje z tym regularnie, co do celu pętli.
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
źródło
count
jakby kolumna była zerowalna. Jeśli zawiera wartości zerowe, musisz odjąć 1.