Penafian : Beberapa hal dalam jawaban ini dapat membuat DBA tersentak. Saya mendekatinya dari sudut pandang kinerja murni - cara mendapatkan Indeks Mencari ketika Anda selalu mendapatkan Indeks Scan.
Dengan hal itu, ini dia.
Permintaan Anda adalah apa yang dikenal sebagai "permintaan wastafel dapur" - satu permintaan yang dimaksudkan untuk memenuhi berbagai kondisi pencarian yang memungkinkan. Jika pengguna menetapkan @statuske nilai, Anda ingin memfilter pada status itu. Jika @statusadalah NULL, mengembalikan semua status, dan sebagainya.
Ini menimbulkan masalah dengan pengindeksan, tetapi mereka tidak terkait dengan sargability, karena semua kondisi pencarian Anda adalah kriteria "sama dengan".
Ini masuk akal:
WHERE [status]=@status
Ini tidak masuk akal karena SQL Server perlu mengevaluasi ISNULL([status], 0)untuk setiap baris alih-alih mencari nilai tunggal dalam indeks:
WHERE ISNULL([status], 0)=@status
Saya telah menciptakan kembali masalah wastafel dapur dalam bentuk yang lebih sederhana:
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);
Jika Anda mencoba yang berikut ini, Anda akan mendapatkan Pemindaian Indeks, meskipun A adalah kolom pertama dari indeks:
DECLARE @a int=4, @b int=NULL;
SELECT *
FROM #work
WHERE (@a IS NULL OR @a=A) AND
(@b IS NULL OR @b=B);
Ini, bagaimanapun, menghasilkan Indeks Mencari:
DECLARE @a int=4, @b int=NULL;
SELECT *
FROM #work
WHERE @a=A AND
@b IS NULL;
Selama Anda menggunakan jumlah parameter yang dapat dikelola (dua dalam kasus Anda), Anda mungkin bisa hanya UNIONsekelompok permintaan pencarian - pada dasarnya semua permutasi kriteria pencarian. Jika Anda memiliki tiga kriteria, ini akan terlihat berantakan, dengan empat kriteria itu akan sepenuhnya tidak dapat dikelola. Anda sudah diperingatkan.
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;
Untuk yang ketiga dari keempat untuk menggunakan Indeks Mencari, Anda akan memerlukan indeks kedua (B, A). Begini cara kueri Anda terlihat dengan perubahan-perubahan ini (termasuk refactoring saya atas kueri agar lebih mudah dibaca).
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='');
... plus Anda akan memerlukan indeks tambahan Employeedengan dua kolom indeks dibalik.
Untuk kelengkapan, saya harus menyebutkan bahwa x=@xsecara implisit berarti itu xtidak mungkin NULLkarena NULLtidak pernah sama dengan NULL. Itu sedikit menyederhanakan kueri.
Dan, ya, jawaban SQL dinamis Aaron Bertrand adalah pilihan yang lebih baik dalam kebanyakan kasus (yaitu kapan pun Anda dapat hidup dengan kompilasi).
@Status?