2014-01-28 4 views
1

SQL Server 2008 R2에서 성능 문제가 발생합니다. 쿼리 최적화 프로그램으로 범위를 좁혔습니다. 나는 "왜 이것이 일어나는가, 아니면 버그인가?"라는 결정적인 것을 찾고있다.인덱스를 사용하지 않는 쿼리 최적화

이 예제를 사용 하겠지만 동일한 시나리오의 여러 sprocs에서도 같은 문제가 발생했습니다. 결제 방법이 포함 된 표가 있습니다. 키 필드는 PaymentMethodId 및 UserId입니다. PaymentMethodId는 int이고, PK입니다. UserId는 클러스터되지 않은 인덱스가있는 nvarchar (255)입니다. 가 @id INT = null이 @userId NVARCHAR (255) = NULL 허용하는 SPROC의 시작 부분에 if 문이있다 : 언급 할 가치가

SPROC의 PARAMS :

쿼리는 다음과 유사합니다 두 매개 변수는 모두 널입니다.

select * from PaymentMethods (nolock) pm 
where (@userId is null or @userId = pm.UserId) 
    and (@id is null or @id = pm.PaymentMethodId) 

@userId가 널인 경우, 옵티마이 저가 첫 번째 절을 항상 참으로 감지 할 것으로 예상합니다. @userId가 null이 아니면 UserId에 인덱스를 사용할 것으로 기대합니다. @id에 대한 기대치가 같습니다.

우리가 보는 것은 데이터베이스가 전체 테이블 스캔을 수행하기 위해 선택한 입력 값과 상관없이입니다. 이것은 독자적으로 관련되어 있지만 흥미로운 부분입니다.

where 절을 다음과 동등한 것으로 업데이트 할 때 indces를 올바르게 사용하고 있습니다.

select * from PaymentMethods (nolock) pm 
where ((@userId is null and pm.UserId is null) OR @userId = pm.UserId) 
    and (@id is null or @id = pm.PaymentMethodId) 

무슨 일입니까? 왜 "@userId가 null입니까?"는 모든 레코드에 대해 고려됩니다 (또는 그럴까요?) 아니면 키보드 앞에 앉아있는 실제 문제입니까?

+1

(a) 테이블이 작거나 (행 수가 적음) 또는 (b) 'SELECT *'를 사용했기 때문에 인덱스가 "표지"할 수있는 방법이 없기 때문일 수 있습니다. 쿼리가 필요하므로 많은 키 검색이 필요하며 궁극적으로 전체 테이블 검색을 수행하는 것보다 비용이 많이 듭니다. –

+0

테이블에 1130 만 레코드가 있고 실제 쿼리는 * 대신 이름으로 필드를 호출합니다. – Jon

+1

쿼리 계획의 스냅 샷을 게시하십시오. 테이블 정의 및 샘플 데이터가 있습니까? 약간의 기록. –

답변

1

당신의 sp가 느린 데는 여러 가지 이유가있을 수 있습니다. 예를 들어, 저장 프로 시저는 처음에 sp를 실행할 때 매개 변수 값에 따라 계획을 만듭니다. 즉, 새 값이 다른 계획의 이점을 얻을 수있는 완전히 다른 결과 집합을 반환 할 수있는 경우에도 동일한 계획을 얻습니다. 동적 SQL을 사용하거나 OPTION(RECOMPILE)으로 sp를 실행하면 최적화 프로그램이 다른 실행 계획을 작성할 수 있습니다. 이것은 하나의 예입니다 :

CREATE STORED PROCEDURE dbo.Test @userid INT, @id INT 
AS 

DECLARE @sql NVARCHAR(4000) 

SET @sql = N'SELECT * 
      FROM PaymentMethods pm 
      WHERE 1 = 1' 

SET @sql = @sql + 
      CASE 
       WHEN @userid IS NOT NULL THEN N' AND pm.UserId = @userid ' 
       ELSE N'' 
      END + 
      CASE 
       WHEN @id IS NOT NULL THEN N' AND pm.PaymentMethodId = @id ' 
       ELSE N'' 
      END 

EXEC sp_executesql @sql, N'@userid INT, @id INT', @userid, @id; 
+0

동적 SQL이 해결책이 아니지만 계획 작성과 관련한 의견은 제가 찾고있는 것이 었습니다. 고맙습니다. if 문을 사용하고 지금은 별도의 쿼리를 사용하기로 결정했습니다. – Jon

관련 문제