Isenção de responsabilidade : algumas das coisas nesta resposta podem fazer um DBA recuar. Estou abordando isso do ponto de vista do desempenho puro - como obter pesquisas de índice quando você sempre obtém verificações de índice.
Com isso fora do caminho, aqui vai.
Sua consulta é conhecida como "consulta de pia da cozinha" - uma consulta única destinada a atender a várias condições possíveis de pesquisa. Se o usuário definir @status
um valor, você deseja filtrar esse status. Se @status
estiver NULL
, retorne todos os status e assim por diante.
Isso apresenta problemas com a indexação, mas eles não estão relacionados à capacidade de Sargability, porque todas as suas condições de pesquisa são "iguais a" critérios.
Isso é sargável:
WHERE [status]=@status
Isso não é sargável porque o SQL Server precisa avaliar ISNULL([status], 0)
para cada linha em vez de procurar um único valor no índice:
WHERE ISNULL([status], 0)=@status
Recriei o problema da pia da cozinha de uma forma mais simples:
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);
Se você tentar o seguinte, você obterá uma verificação de índice, mesmo que A seja a primeira coluna do índice:
DECLARE @a int=4, @b int=NULL;
SELECT *
FROM #work
WHERE (@a IS NULL OR @a=A) AND
(@b IS NULL OR @b=B);
Isso, no entanto, produz uma busca por índice:
DECLARE @a int=4, @b int=NULL;
SELECT *
FROM #work
WHERE @a=A AND
@b IS NULL;
Enquanto você estiver usando uma quantidade gerenciável de parâmetros (dois no seu caso), provavelmente poderá fazer UNION
várias consultas de pesquisa - basicamente todas as permutações dos critérios de pesquisa. Se você tiver três critérios, isso parecerá confuso; com quatro, será completamente incontrolável. Voce foi avisado.
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;
Para o terceiro desses quatro usar uma busca de índice, você precisará de um segundo índice (B, A)
. Veja como sua consulta pode parecer com essas alterações (incluindo minha refatoração da consulta para torná-la mais legível).
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='');
... mais você precisará de um índice adicional Employee
com as duas colunas de índice invertidas.
Para completar, devo mencionar que x=@x
implicitamente significa que x
não pode ser NULL
porque NULL
nunca é igual a NULL
. Isso simplifica um pouco a consulta.
E sim, a resposta SQL dinâmica de Aaron Bertrand é uma escolha melhor na maioria dos casos (ou seja, sempre que você pode conviver com as recompilações).
@Status
?