Reputation: 1666
I'd like to know how I can increase the performance and efficiency of my SQL statement. Does anyone have some ideas or advices?
DECLARE @RoleName NVARCHAR(MAX)
DECLARE @result INT
SELECT @result = COUNT(DurchlaufVorgang.Durchlaufname)
FROM DurchlaufVorgang
INNER JOIN RoleDepartment
ON DurchlaufVorgang.AbteilungID = RoleDepartment.ID
WHERE DurchlaufVorgang.Depricated = 'FALSE'
AND RoleDepartment.RoleName = @RoleName
AND RoleDepartment.Depricated = 'FALSE'
SELECT Antraege.AntragID
FROM ArtikelMitteilung,
Antraege
WHERE ArtikelMitteilung.Status = 'Opened'
AND Antraege.AntragID NOT IN
(SELECT Antraege.AntragID
FROM Vorgang,
Antraege
WHERE Vorgang.StepID IN
(SELECT DurchlaufVorgang.ID
FROM DurchlaufVorgang
INNER JOIN RoleDepartment
ON DurchlaufVorgang.AbteilungID = RoleDepartment.ID
WHERE DurchlaufVorgang.Depricated = 'FALSE'
AND RoleDepartment.RoleName = @RoleName
AND RoleDepartment.Depricated = 'FALSE')
AND Vorgang.AntragsID = Antraege.ID
GROUP BY Antraege.AntragID
HAVING COUNT(Antraege.AntragID) >= @result)
AND ArtikelMitteilung.AntragsID = Antraege.ID
GROUP BY Antraege.AntragID
I'm grateful for your help.
Upvotes: 0
Views: 209
Reputation: 1081
depending on the size of tables it may help a lot to get your list into an indexed column.
declare @tab (AntragID int primary key clustered)
insert @tab
(AntragID)
SELECT Antraege.AntragID
FROM Vorgang,
Antraege
WHERE Vorgang.StepID IN
(SELECT DurchlaufVorgang.ID
FROM DurchlaufVorgang
INNER JOIN RoleDepartment
ON DurchlaufVorgang.AbteilungID = RoleDepartment.ID
WHERE DurchlaufVorgang.Depricated = 'FALSE'
AND RoleDepartment.RoleName = @RoleName
AND RoleDepartment.Depricated = 'FALSE')
AND Vorgang.AntragsID = Antraege.ID
GROUP BY Antraege.AntragID
HAVING COUNT(Antraege.AntragID) >= @result
SELECT Antraege.AntragID
FROM
Antraege
INNER JOIN ArtikelMitteilung
ON Antraege.ID = ArtikelMitteilung.AntragsID
LEFT JOIN @tab x
ON Antraege.AntragID = X.AntragID
WHERE
ArtikelMitteilung.Status = 'Opened' AND
X.AntragID IS NULL
GROUP BY
if a unique AntragID is not returned from the subquery use a temp table instead of the table variable and create an index on AntragID.
create table #tab (AntragID int)
create clustered index cix_antragid_tab on #tab(AntragID)
insert #tab
(AntragID)
SELECT Antraege.AntragID
FROM Vorgang,
Antraege
WHERE Vorgang.StepID IN
(SELECT DurchlaufVorgang.ID
FROM DurchlaufVorgang
INNER JOIN RoleDepartment
ON DurchlaufVorgang.AbteilungID = RoleDepartment.ID
WHERE DurchlaufVorgang.Depricated = 'FALSE'
AND RoleDepartment.RoleName = @RoleName
AND RoleDepartment.Depricated = 'FALSE')
AND Vorgang.AntragsID = Antraege.ID
GROUP BY Antraege.AntragID
HAVING COUNT(Antraege.AntragID) >= @result
SELECT Antraege.AntragID
FROM
Antraege
INNER JOIN ArtikelMitteilung
ON Antraege.ID = ArtikelMitteilung.AntragsID
LEFT JOIN #tab x
ON Antraege.AntragID = X.AntragID
WHERE
ArtikelMitteilung.Status = 'Opened' AND
X.AntragID IS NULL
GROUP BY
It would be possible to optimise the logic of the query if you post the exec plan.
Upvotes: 1
Reputation: 112772
NOT IN clauses are often not very efficient. Try to use a LEFT JOIN instead. Then test if AntragID in the joined table (on the right side) IS NULL.
SELECT *
FROM
Antrage A
LEFT JOIN Antrage B
ON A.AntragID = B.AntragID
WHERE
B.AntragID IS NULL AND
...
SELECT Antraege.AntragID
FROM
Antraege
INNER JOIN ArtikelMitteilung
ON Antraege.ID = ArtikelMitteilung.AntragsID
LEFT JOIN
(SELECT Antraege.AntragID
FROM Vorgang,
Antraege
WHERE Vorgang.StepID IN
(SELECT DurchlaufVorgang.ID
FROM DurchlaufVorgang
INNER JOIN RoleDepartment
ON DurchlaufVorgang.AbteilungID = RoleDepartment.ID
WHERE DurchlaufVorgang.Depricated = 'FALSE'
AND RoleDepartment.RoleName = @RoleName
AND RoleDepartment.Depricated = 'FALSE')
AND Vorgang.AntragsID = Antraege.ID
GROUP BY Antraege.AntragID
HAVING COUNT(Antraege.AntragID) >= @result) X
ON Antraege.AntragID = X.AntragID
WHERE
ArtikelMitteilung.Status = 'Opened' AND
X.AntragID IS NULL
GROUP BY
Antraege.AntragID
Upvotes: -1
Reputation: 5635
Look at the actual query plan, and see where you have index scans and table scans. Find ways to use index seeks to remove those bottlenecks.
I might guess that all of the predicates you have are not indexed, and perhaps the most selective predicates could be indexed, which would greatly help the query planner to choose index seeks to identity the rows to return.
You could also try using a NOT EXISTS
form instead of your NOT IN
form in the WHERE clause. Sometimes that can help, and you should run examine the query execution plan for each.
edit:
Also remove redundant code. For example,
(SELECT Antraege.AntragID
FROM Vorgang,
Antraege
WHERE Vorgang.StepID IN
(/* your subquery */)
AND Vorgang.AntragsID = Antraege.ID
GROUP BY Antraege.AntragID
HAVING COUNT(Antraege.AntragID) >= @result)
can be simplified:
(SELECT Vorgang.AntragsID
FROM Vorgang
WHERE Vorgang.StepID IN
(/* your subquery */)
GROUP BY Vorgang.AntragsID
HAVING COUNT(Vorgang.AntragsID) >= @result)
Upvotes: 1
Reputation: 13549
You're not doing anything glaringly wrong in your query. The SQL optimizer will take a large statement like that and figure out the best way to execute it. Where you can run into problems is if your indices are fragmented or non-existent.
From SQL Server Management Studio, click on Show Execution Plan and see if it suggests any additional indices. De-fragment your indices (you can just drop and re-add them if you're in a testing environment).
If your intuition is that a big statement is bad for performance, that should not be the case here. In fact, it should help the optimizer because it gives it more choices on how to execute it.
Upvotes: 1