2009-10-23 2 views
1

테이블이 있는데 이것을 History이라고합시다. 기본 키 (일명 Clustered Index)는 HIST_ID입니다. 테이블에는 개발 DB에 약 2300 개의 행이 있습니다. 이제 다음과 같은 두 가지 쿼리를 고려하십시오SQL Server, 인덱스 및 매개 변수가있는 특별한 경우

쿼리 1 :

declare @x int 
set @x = 14289 

select * from History where [email protected] 

질의 2 :

declare @x int 
set @x = 14289 

select * from History where [email protected] or @x is null 

유일한 차이점은 끝에 or @x is null입니다. 그러나 첫 번째 쿼리는 두 번째 인덱스 스캔 인 인덱스 찾기를 수행합니다. 뭐라 구요?

선결제 응답 - 아니요, 옵션 (재 컴파일)이 도움이되지 않습니다.

추가 : 견고한 논증의 사실을 말하고 싶습니다. 추측이 아닙니다. 나는 이것에 대한 십여 가지의 가능한 이유를 생각할 수있다. 하지만 여기에 무슨 문제가 있습니까?

답변

0

나는 그것이 유리하다고 옵티마이 저는 판단합니다. 당신이 이런 식으로 쿼리를 다시 작성할 수 있습니다

select * from History where [email protected] 
union all 
select * from History where @x is null 

을 쓴 것처럼 대안이 같은 계획을 사용하는 것입니다,하지만 난 최적화는 그 자체로이 일을 할 수있는 확신합니다. 얼마나 많은 null 값을 갖고 있습니까?

편집 : 내가 질문을 잘못 읽고, (@x = hist_id 또는 hist_id가 null) WHERE (@x = hist_id가 필요함)을 원한다고 생각합니다. 사실 당신은 역동적 인 기준을 원합니다. this article을 확인하십시오. 이 종류의 쿼리는 WITH (RECOMPILE)을 지정하면 SQL2k8에서 작동한다고 가정했으나 불쾌한 버그로 인해이 지원이 제거되었습니다.

+0

에헴, 자세히보세요! "is null"은 @x가 아니라 테이블에 대해 수행됩니다! 그것은 일정한 FALSE 식입니다! –

+0

그의 노조에있는 두 번째 SELECT 문은 ** 항상 ** 빈 세트를 반환합니다. @x의 값은 14289이며 null이 아닙니다. –

+0

누적 업데이트 5가 릴리스 된 후에 지원이 다시 추가되었습니다. 최신 업데이트를 얻은 경우 광고 된대로 작동합니다. – NotMe

1

필자는이 계획이 /로 전달되는 매개 변수와 별개로 생산되고 있으므로 본질적으로 모든 행을 반환하는 요구 사항 (@x 값에 따라 다름)이 있음을 제안합니다. 이와 같은 쿼리 계획은 그것이받을 수있는 매개 변수의 최악의 시나리오를 다루고 있습니다.

@x에 대한 입력이 널 (NULL)이면, 모든 행은 항상 참이 리턴 된 리터럴 방정식/술어를 만족하므로 모든 행을 리턴하도록 강제됩니다. @x의 모든 값을 포함하는 쿼리 계획의 경우 검사를 수행하는 계획을 생성해야합니다.

+0

나는 MSSQL이이를 수정해야하는 "매개 변수 스니핑 (parameter sniffing)"을 할 수 있다고 읽었습니다. 실제로 옵션 (재 컴파일)은 그렇게해야합니다 -하지만 그렇게하지는 마십시오. –

+0

SARG라는 용어를 사용하는이 개념에 대한보다 기술적 인 설명이있을 것입니다. 그러나이 버전은 좀 더 이해하기 쉽습니다. –

+0

매개 변수 스니핑 기능은 쿼리의 리터럴 값을 매개 변수로 바꾸려고하므로 더 많은 쿼리 계획 캐시 히트가 있습니다. 리터럴이 아닌 매개 변수를 이미 전달하고 있으므로 문제가 없으므로 스니핑하므로 다시 컴파일하면 변경되지 않습니다. – Andrew

0

물론 색인 스캔입니다.

"@x IS NULL"에 대해 의미있는 조건이 없기 때문에 클러스터 된 인덱스 스캔 = 테이블 스캔입니다.

매개 변수가있는 캐시 된 계획은 일반적이며 @x = NULL 또는 @x = value에서 작동합니다. @x를 정의하지 않으면 동일한 계획을 세워야합니다.

"12345 IS NULL"로 코딩 한 경우이 코드가 감지되고 무시됩니다.

쿼리 계획에서 상수를 처리하는 방법에 대한 블로그 기사를 찾을 수 없습니다. 요점은 그들이 일반화되어 있고 계획이 재사용 될 수있는 단락이 발생하지 않는다는 것입니다.

관련 문제