WHERE 절의 변수에 대해 null 검사를 수행하는 방법이 한 번만 발생합니까?


12

다음과 같은 큰 테이블에 대한 쿼리가 있습니다.

declare @myIdParam int = 1

select * 
from myTable
where (@myIdParam is null or myTable.Id = @myIdParam)

where 절에 이와 유사한 조건이 몇 가지 있으며 많은 조인도 있지만 이것은 요약입니다.

효과적으로 @myIdParam이 null이면이 매개 변수를 사용하여 결과를 제한하지 않습니다.

나는 DB 전문가는 아니지만 테스트 에서이 NULL 검사는 모든 레코드에 대해 수행되고 어떤 식 으로든 최적화되지 않은 것처럼 보입니다.

null 검사를 제거하고 매개 변수가 null이 아니라고 가정하면 쿼리가 즉시 반환됩니다. 그렇지 않으면 최대 10 초가 걸립니다.

런타임에 확인이 한 번만 수행되도록 이것을 최적화하는 방법이 있습니까?


1
이 답변을보십시오 : stackoverflow.com/questions/3415582/… tl; dr 사용OPTION(RECOMPILE)
vercelli

@vercelli 이것은 트릭을 수행합니다. 이 질문은 실제로 선택적 매개 변수에 관한 것으로 생각하면 연결된 매개 변수와 중복됩니다.
Mystagogue

아마 6 년 전의 글일 것입니다. SqlServer 2014 또는 2016에는 새로운 접근 방식이있을 수 있습니다. (재 컴파일하지 않고 2014 년에 테스트했으며 영원히 걸렸습니다)
vercelli

실제 쿼리에는 많은 선택적 매개 변수가 있으므로 동적 SQL은 최상의 성능을 제공합니다. 주제에 대한 자세한 기사는 sommarskog.se/dyn-search.html 을 참조하십시오 .
Dan Guzman

질문 vercelli linked에 설명 된대로 WITH RECOMPILE을 사용하는 @DanGuzman은 쿼리 시간을 1 분 미만에서 매우 선택적 기준으로 실제로 즉각적으로 단축했습니다. 나는 이것이 성능과 가독성의 균형을 맞추기에 가장 좋은 옵션이라고 생각합니다.
Mystagogue

답변:


8

한 가지 방법은 null 검사를 사용하여 where 절의 해당 부분을 선택적으로 추가하는 동적 SQL을 사용하는 것입니다.

declare @myIdParam int = 1
declare @vc_dynamicsql varchar(max)

set @vc_dynamicsql = 'select * from myTable where 1=1'

if @myIdParam is not null
    set @vc_dynamicsql = @vc_dynamicsql + ' and  myTable.Id = @myIdParam'

EXECUTE sp_executesql @vc_dynamicsql

2
나는 이것을하지 않는 것을 정말로 원하지만 해결책입니다. 내 희망은 누군가가 훨씬 나은 사람과 함께 오는 것입니다.
Mystagogue

1
이것이이 검색 쿼리 클래스를 처리하는 가장 좋은 방법입니다. @vercelli언급stackoverflow 답변 에는이를 수행하는 방법에 대한 훌륭한 참조가 포함되어 있습니다.
Max Vernon

이것이 가장 좋은 방법이지만 @params 매개 변수 sp_ExecuteSQL가 누락되었으며 @vc_dynamicsql매개 변수가이어야 한다는 것을 알았 습니다 NVARCHAR.
제임스 앤더슨

4

예를 들어 열 'ISNULL (@var, table.col)'주위에 함수를 넣을 때마다 인덱스를 사용하는 SQL의 기능이 제거됩니다. 단일 쿼리로 유지하려면 이것이 가장 성능이 좋은 옵션입니다.

@var IS NULL or @var = table.col

그렇지 않으면 두 가지 옵션이 있습니다. 첫 번째는 동적 SQL이며 @Mystagogue의 대답은 충분합니다. 그렇지 않으면 다음과 같은 두 가지 쿼리를 넣을 수 있습니다.

IF @var is NULL
     SELECT * FROM table
ELSE
     SELECT * FROM table WHERE @var = col

이 형식과 동적 SQL 모두 실제로 각 쿼리마다 다른 쿼리 계획을 얻습니다 (성능 향상).


질문의 Sql은 ISNULL 또는 다른 함수를 사용하지 않습니다.
Mystagogue

@Mystagogue 지금 삭제 된 답변을 참조하고있었습니다.
케네스 피셔

0

글쎄, 당신은 할 수 있습니다 :

declare @myIdParam int = 1;

select *
from myTable
where nullif(@myIdParam, myTable.Id) is null;

그러나 nullif()함수는 본질적으로 위에 래퍼 라는 것을 명심하십시오 case. 마 법적으로 OR쿼리를 제거 하여 속도 를 높이는 것은 총알이 아닙니다 .


where 절에 함수를 사용하면 인덱스의 사용을 방지하기 때문에 성능에 부정적인 영향을줍니다 (또는 들었어요 그래서)
Mystagogue

@Mystagogue, 그렇습니다-일반적으로 검색 조건을 SARGable로 만듭니다. 아아, 이것은 동적 SQL 또는 다중에 의지하지 않고 귀하의 질문에 대답하는 방법을 아는 유일한 방법 UNION입니다. 이 정확한 작업을 수행 할 때 동적 SQL을 선택했습니다.
Roger Wolf
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.