이 패턴
column = @argument OR (@argument IS NULL AND column IS NULL)
로 교체 가능
EXISTS (SELECT column INTERSECT SELECT @argument)
이를 통해 NULL을 NULL과 일치시키고 엔진이 column
효율적으로 인덱스를 사용할 수 있습니다. 이 기술에 대한 훌륭한 심층 분석을 위해 Paul White의 블로그 기사를 참조하십시오.
특정 경우에 두 개의 인수가 있으므로 동일한 일치 기술을 함께 사용할 수 있습니다. 이렇게 @Blah
하면 전체 WHERE 절을 다소 간결하게 다시 작성할 수 있습니다.
WHERE
EXISTS (SELECT a.Blah, a.VersionId INTERSECT SELECT @Blah, @VersionId)
에 대한 색인으로 빠르게 작동합니다 (a.Blah, a.VersionId)
.
아니면 쿼리 최적화 프로그램이 본질적으로 동일합니까?
이 경우에 그렇습니다. SQL Server 2005 이후의 모든 버전 (최소한)에서 옵티마이 저는 패턴을 인식하고 col = @var OR (@var IS NULL AND col IS NULL)
이를 적절한 IS
비교로 바꿀 수 있습니다. 내부 재 작성 일치에 의존하기 때문에 이것이 항상 신뢰할 수없는 복잡한 경우가있을 수 있습니다.
2008 SP1 CU5 의 SQL Server 버전 에는 매개 변수 포함 최적화 를 사용하는 옵션도 있습니다. OPTION (RECOMPILE)
여기서 매개 변수 또는 변수의 런타임 값은 컴파일 전에 리터럴로 쿼리에 포함됩니다.
따라서 적어도이 경우에는 선택의 여지가 스타일의 문제이지만 INTERSECT
건축은 명백하고 콤팩트합니다.
다음 예제는 각 변형에 대한 '동일한'실행 계획을 보여줍니다 (리터럴 대 변수 참조는 제외됨).
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);