Avertissement : Certains éléments de cette réponse peuvent faire tressaillir DBA. Je l'aborde du point de vue des performances pures - comment obtenir des recherches d'index lorsque vous obtenez toujours des analyses d'index.
Avec cela à l'écart, voici.
Votre requête est ce que l'on appelle une "requête d'évier de cuisine" - une requête unique destinée à répondre à une gamme de conditions de recherche possibles. Si l'utilisateur définit @status
une valeur, vous souhaitez filtrer sur cet état. Si @status
c'est le cas NULL
, renvoyez tous les statuts, etc.
Cela pose des problèmes d'indexation, mais ils ne sont pas liés à la sargabilité, car toutes vos conditions de recherche sont "égales" aux critères.
C'est discutable:
WHERE [status]=@status
Ce n'est pas discutable car SQL Server doit évaluer ISNULL([status], 0)
pour chaque ligne au lieu de rechercher une seule valeur dans l'index:
WHERE ISNULL([status], 0)=@status
J'ai recréé le problème de l'évier de cuisine sous une forme plus simple:
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);
Si vous essayez ce qui suit, vous obtiendrez une analyse d'index, même si A est la première colonne de l'index:
DECLARE @a int=4, @b int=NULL;
SELECT *
FROM #work
WHERE (@a IS NULL OR @a=A) AND
(@b IS NULL OR @b=B);
Cependant, cela produit une recherche d'index:
DECLARE @a int=4, @b int=NULL;
SELECT *
FROM #work
WHERE @a=A AND
@b IS NULL;
Tant que vous utilisez une quantité gérable de paramètres (deux dans votre cas), vous pourriez probablement juste UNION
un tas de requêtes de recherche - essentiellement toutes les permutations des critères de recherche. Si vous avez trois critères, cela semblera compliqué, avec quatre, ce sera complètement ingérable. Tu as été prévenu.
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;
Pour que le troisième de ces quatre utilise une recherche d'index, vous aurez cependant besoin d'un deuxième index (B, A)
. Voici à quoi pourrait ressembler votre requête avec ces modifications (y compris ma refactorisation de la requête pour la rendre plus lisible).
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='');
... en plus, vous aurez besoin d'un index supplémentaire Employee
avec les deux colonnes d'index inversées.
Pour être complet, je dois mentionner que cela x=@x
signifie implicitement que x
cela ne peut pas être NULL
parce que NULL
n'est jamais égal à NULL
. Cela simplifie un peu la requête.
Et, oui, la réponse SQL dynamique d'Aaron Bertrand est un meilleur choix dans la plupart des cas (c'est-à-dire chaque fois que vous pouvez vivre avec les recompilations).
@Status
?