Bu desen
column = @argument OR (@argument IS NULL AND column IS NULL)
ile değiştirilebilir
EXISTS (SELECT column INTERSECT SELECT @argument)
Bu, bir NULL ile bir NULL değerini eşleştirmenize ve motorun bir dizini column
verimli bir şekilde kullanmasına izin verecektir . Bu tekniğin mükemmel bir derinlemesine analizi için sizi Paul White'ın blog makalesine yönlendiriyorum:
Özel durumunuzda iki argüman olduğundan, aynı eşleştirme tekniğini kullanabilirsiniz @Blah
- bu şekilde WHERE yan tümünün tamamını az çok özlü bir şekilde yeniden yazabilirsiniz:
WHERE
EXISTS (SELECT a.Blah, a.VersionId INTERSECT SELECT @Blah, @VersionId)
Bu bir indeks ile hızlı bir şekilde çalışacaktır (a.Blah, a.VersionId)
.
Veya sorgu optimizer aslında aynı yapar?
Bu durumda, evet. SQL Server 2005'ten sonraki tüm sürümlerde (en azından), iyileştirici kalıbı tanıyabilir col = @var OR (@var IS NULL AND col IS NULL)
ve uygun IS
karşılaştırmayla değiştirebilir. Bu, dahili yeniden yazma eşleşmesine dayanır, bu nedenle bunun her zaman güvenilir olmadığı daha karmaşık durumlar olabilir.
SQL Server sürümlerinde 2008 SP1 5 PB Anin gelen , ayrıca kullanma seçeneği Parametre Gömme Optimizasyonu aracılığıyla OPTION (RECOMPILE)
herhangi bir parametre veya değişken çalışma zamanı değeri derleme önce bir değişmez olarak sorguda gömülü olduğu yerde.
Yani, en azından büyük ölçüde, bu durumda seçim bir stil meselesidir, ancak INTERSECT
inşaat inkar edilemez derecede kompakt ve zariftir.
Aşağıdaki örnekler, her bir varyasyon için 'aynı' yürütme planını gösterir (değişmezler ve değişken referanslar hariç):
DECLARE @T AS table
(
c1 integer NULL,
c2 integer NULL,
c3 integer NULL
UNIQUE CLUSTERED (c1, c2)
);
-- Some data
INSERT @T
(c1, c2, c3)
SELECT 1, 1, 1 UNION ALL
SELECT 2, 2, 2 UNION ALL
SELECT NULL, NULL, NULL UNION ALL
SELECT 3, 3, 3;
-- Filtering conditions
DECLARE
@c1 integer,
@c2 integer;
SELECT
@c1 = NULL,
@c2 = NULL;
-- Writing the NULL-handling out explicitly
SELECT *
FROM @T AS T
WHERE
(
T.c1 = @c1
OR (@c1 IS NULL AND T.c1 IS NULL)
)
AND
(
T.c2 = @c2
OR (@c2 IS NULL AND T.c2 IS NULL)
);
-- Using INTERSECT
SELECT *
FROM @T AS T
WHERE EXISTS
(
SELECT T.c1, T.c2
INTERSECT
SELECT @c1, @c2
);
-- Using separate queries
IF @c1 IS NULL AND @c2 IS NULL
SELECT *
FROM @T AS T
WHERE T.c1 IS NULL
AND T.c2 IS NULL
ELSE IF @c1 IS NULL
SELECT *
FROM @T AS T
WHERE T.c1 IS NULL
AND T.c2 = @c2
ELSE IF @c2 IS NULL
SELECT *
FROM @T AS T
WHERE T.c1 = @c1
AND T.c2 IS NULL
ELSE
SELECT *
FROM @T AS T
WHERE T.c1 = @c1
AND T.c2 = @c2;
-- Using OPTION (RECOMPILE)
-- Requires 2008 SP1 CU5 or later
SELECT *
FROM @T AS T
WHERE
(
T.c1 = @c1
OR (@c1 IS NULL AND T.c1 IS NULL)
)
AND
(
T.c2 = @c2
OR (@c2 IS NULL AND T.c2 IS NULL)
)
OPTION (RECOMPILE);