Haftungsausschluss : Einige der Dinge in dieser Antwort können einen DBA zusammenzucken lassen. Ich gehe es von einem reinen Performance-Standpunkt aus an - wie man Index-Suchanfragen erhält, wenn man immer Index-Scans erhält.
Damit geht es aus dem Weg.
Ihre Abfrage wird als "Abfrage für Küchenspülen" bezeichnet - eine einzelne Abfrage, die eine Reihe möglicher Suchbedingungen abdeckt. Wenn der Benutzer @statuseinen Wert festlegt , möchten Sie nach diesem Status filtern. Wenn dies der Fall @statusist NULL, geben Sie alle Status usw. zurück.
Dies führt zu Problemen bei der Indizierung, die jedoch nicht mit der Sargabilität zusammenhängen, da alle Suchbedingungen den Kriterien entsprechen.
Das ist sargable:
WHERE [status]=@status
Dies ist nicht sargable, da SQL Server ISNULL([status], 0)für jede Zeile auswerten muss, anstatt einen einzelnen Wert im Index nachzuschlagen :
WHERE ISNULL([status], 0)=@status
Ich habe das Problem mit dem Spülbecken in einer einfacheren Form nachgebildet:
CREATE TABLE #work (
A int NOT NULL,
B int NOT NULL
);
CREATE UNIQUE INDEX #work_ix1 ON #work (A, B);
INSERT INTO #work (A, B)
VALUES (1, 1), (2, 1),
(3, 1), (4, 1),
(5, 2), (6, 2),
(7, 2), (8, 3),
(9, 3), (10, 3);
Wenn Sie Folgendes versuchen, erhalten Sie einen Index-Scan, obwohl A die erste Spalte des Index ist:
DECLARE @a int=4, @b int=NULL;
SELECT *
FROM #work
WHERE (@a IS NULL OR @a=A) AND
(@b IS NULL OR @b=B);
Dies führt jedoch zu einer Indexsuche:
DECLARE @a int=4, @b int=NULL;
SELECT *
FROM #work
WHERE @a=A AND
@b IS NULL;
Solange Sie eine überschaubare Anzahl von Parametern verwenden (in Ihrem Fall zwei), könnten Sie wahrscheinlich nur UNIONeine Reihe von Suchabfragen durchführen - im Grunde alle Permutationen von Suchkriterien. Wenn Sie drei Kriterien haben, sieht dies chaotisch aus, bei vier ist es völlig unüberschaubar. Du wurdest gewarnt.
DECLARE @a int=4, @b int=NULL;
SELECT *
FROM #work
WHERE @a=A AND
@b IS NULL
UNION ALL
SELECT *
FROM #work
WHERE @a=A AND
@b=B
UNION ALL
SELECT *
FROM #work
WHERE @a IS NULL AND
@b=B
UNION ALL
SELECT *
FROM #work
WHERE @a IS NULL AND
@b IS NULL;
Damit der dritte dieser vier einen Index-Suchvorgang verwenden kann, benötigen Sie jedoch einen zweiten Index (B, A). So könnte Ihre Abfrage mit diesen Änderungen aussehen (einschließlich meines Refactorings der Abfrage, um sie besser lesbar zu machen).
DECLARE @Status int = NULL,
@IsUserGotAnActiveDirectoryUser bit = NULL;
SELECT [IdNumber], [Code], [Status], [Sex], [FirstName], [LastName],
[Profession], [BirthDate], [HireDate], [ActiveDirectoryUser]
FROM Employee
WHERE [Status]=@Status AND
@IsUserGotAnActiveDirectoryUser IS NULL
UNION ALL
SELECT [IdNumber], [Code], [Status], [Sex], [FirstName], [LastName],
[Profession], [BirthDate], [HireDate], [ActiveDirectoryUser]
FROM Employee
WHERE [Status]=@Status AND
@IsUserGotAnActiveDirectoryUser=1 AND ActiveDirectoryUser<>''
UNION ALL
SELECT [IdNumber], [Code], [Status], [Sex], [FirstName], [LastName],
[Profession], [BirthDate], [HireDate], [ActiveDirectoryUser]
FROM Employee
WHERE [Status]=@Status AND
@IsUserGotAnActiveDirectoryUser=0 AND (ActiveDirectoryUser IS NULL OR ActiveDirectoryUser='')
UNION ALL
SELECT [IdNumber], [Code], [Status], [Sex], [FirstName], [LastName],
[Profession], [BirthDate], [HireDate], [ActiveDirectoryUser]
FROM Employee
WHERE @Status IS NULL AND
@IsUserGotAnActiveDirectoryUser IS NULL
UNION ALL
SELECT [IdNumber], [Code], [Status], [Sex], [FirstName], [LastName],
[Profession], [BirthDate], [HireDate], [ActiveDirectoryUser]
FROM Employee
WHERE @Status IS NULL AND
@IsUserGotAnActiveDirectoryUser=1 AND ActiveDirectoryUser<>''
UNION ALL
SELECT [IdNumber], [Code], [Status], [Sex], [FirstName], [LastName],
[Profession], [BirthDate], [HireDate], [ActiveDirectoryUser]
FROM Employee
WHERE @Status IS NULL AND
@IsUserGotAnActiveDirectoryUser=0 AND (ActiveDirectoryUser IS NULL OR ActiveDirectoryUser='');
... und Sie benötigen einen zusätzlichen Index, Employeewobei die beiden Indexspalten vertauscht sind.
Der Vollständigkeit halber sollte ich erwähnen, dass dies x=@ximplizit bedeutet, dass xes nicht sein kann, NULLweil NULLes niemals gleich ist NULL. Das vereinfacht die Abfrage etwas.
Und ja, Aaron Bertrands dynamische SQL-Antwort ist in den meisten Fällen die bessere Wahl (dh wann immer Sie mit den Neukompilierungen leben können).
@Status?