Відмова від відповідальності : Деякі речі в цій відповіді можуть змусити DBA здригнутися. Я підходжу до цього з точки зору чистої продуктивності - як отримати пошукові запити, коли ви завжди отримуєте індекси сканування.
Із цим не виходить, тут іде.
Ваш запит - це те, що відомо як "запит кухонної раковини" - один запит, який повинен забезпечити широкий спектр можливих умов пошуку. Якщо користувач встановив @status
значення, потрібно фільтрувати цей статус. Якщо @status
є NULL
, поверніть усі статуси тощо.
Це спричиняє проблеми з індексуванням, але вони не пов'язані із зручністю пошуку, оскільки всі ваші умови пошуку відповідають критеріям.
Це можна стверджувати:
WHERE [status]=@status
Це не піддається обробці, оскільки SQL Server повинен оцінювати ISNULL([status], 0)
кожен рядок, а не шукати одне значення в індексі:
WHERE ISNULL([status], 0)=@status
Я відтворив кухонну мийку в більш простому вигляді:
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);
Якщо ви спробуєте наступне, ви отримаєте індексне сканування, навіть якщо A є першим стовпцем індексу:
DECLARE @a int=4, @b int=NULL;
SELECT *
FROM #work
WHERE (@a IS NULL OR @a=A) AND
(@b IS NULL OR @b=B);
Це, однак, призводить до пошуку індексу:
DECLARE @a int=4, @b int=NULL;
SELECT *
FROM #work
WHERE @a=A AND
@b IS NULL;
Поки ви використовуєте керовану кількість параметрів (у вашому випадку два), ви, ймовірно, можете просто UNION
купувати запити - в основному всі перестановки критеріїв пошуку. Якщо у вас є три критерії, це буде виглядати безладно, з чотирма це буде абсолютно некеровано. Вас попередили.
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;
Для того, щоб третій із цих чотирьох використав Index Search, вам знадобиться другий індекс на (B, A)
. Ось як може виглядати ваш запит із цими змінами (включаючи рефакторинг запиту, щоб зробити його більш читабельним).
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='');
... плюс вам знадобиться додатковий індекс на Employee
два стовпці індексу.
Для повноти я повинен зазначити, що x=@x
неявно означає, що x
не може бути, NULL
тому що NULL
ніколи не дорівнює NULL
. Це трохи спрощує запит.
І так, динамічна відповідь SQL Аарона Бертран є кращим вибором у більшості випадків (тобто, коли можна жити з перекомпіляціями).
@Status
?