I'm trying to improve the performance of the following query:
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
Currently with my test data it takes about a minute. I have a limited amount of input into changes on the over all stored procedure where this query resides but I can probably get them to modify this one query. Or add an index. I tried adding the following index:
CREATE CLUSTERED INDEX ix_test ON #TempTable(AgentID, RuleId, GroupId, Passed)
And it actually doubled the amount of time the query takes. I get the same effect with a NON-CLUSTERED index.
I tried re-writing it as follows with no effect.
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
Next I tried to use a windowing function like this.
UPDATE [#TempTable]
SET Received = COUNT(DISTINCT (CASE WHEN Passed=1 THEN GroupId ELSE NULL END))
OVER (PARTITION BY AgentId, RuleId)
FROM [#TempTable]
At this point I started to get the error
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near 'distinct'.
So I have two questions. First can you not do a COUNT DISTINCT with the OVER clause or did I just write it incorrectly? And second can anyone suggest an improvement I haven't already tried? FYI this is a SQL Server 2008 R2 Enterprise instance.
EDIT: Here is a link to the original execution plan. I should also note that my big problem is that this query is being run 30-50 times.
https://onedrive.live.com/redir?resid=4C359AF42063BD98%21772
EDIT2: Here is the full loop that the statement is in as requested in the comments. I'm checking with the person who works with this on a regular basis as to the purpose of the 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


countif the column is nullable. If it contains any nulls you need to subtract 1. – Martin Smith May 17 '16 at 07:59