2010-07-06 3 views
2

두 레코드 id 필드 (record1, record2)가있는보기를 각 레코드에 두 번 - 최상위 1000 개를 선택하여 두 번 봅니다.보기는 여러 오히려 큰 테이블, 그리고 그것의 ID 필드는 각각의 ID의 문자열 연결입니다 (이것은보기에 고유 한 ID가 필요한 일부 타사 소프트웨어에 필요했습니다. 행 넘버링은 매우 느립니다). 뷰에 날짜를 비교하는 함수를 호출하는 where 절도 있습니다.추정 된 서브 트리 비용 예상치 않게 꺼짐, 끔찍한 최적화

OPTION (FORCE ORDER)을 사용하지 않으면 예상 실행 계획에서 "조인 조건 없음"경고가 생성됩니다. 순서 지정을 강제하면 실행 계획에는 100 % 비용을 표시하는 여러 노드가 있습니다. 이 노드가

은 무슨 일 것입니다 (이 또는 중첩 루프 35927400000000 높은 CPU 비용과 조인 많이하고 있어요)의의 두 경우 모두, 엔드 포인트에서 예상 하위 트리 비용은보다 규모의 열세 주문 작 실행 계획의 번호는? 그리고 SQL Server가 쿼리를 최적화하는 데 어려움을 겪고있는 이유는 무엇입니까?

연결된 문자열의보기에 색인을 추가하고 NOEXPAND 테이블 힌트를 사용하면 문제가 완전히 해결되었습니다. 그것은 12 초 모두에 달했다. 하지만 왜 SQL은 그렇게 나빠졌 는가? (심지어 인덱스를 추가 한 후 noexpand 힌트를 요구할지라도)?

CU와 SQL 서버 2008 SP1을 실행 8.

보기 :

SELECT 
    dbo.fnGetCombinedTwoPartKey(N.NameID,A.AddressID) AS NameAddressKey, 
    [other fields] 

FROM  
    [7 joined tables] 
WHERE dbo.fnDatesAreOverlapping(N.dtmValidStartDate,N.dtmValidEndDate,A.dtmValidStartDate,A.dtmValidEndDate) = 1 

쿼리

SELECT TOP 1000 
    vw1.strFullName, 
    vw1.strAddress1, 
    vw1.strCity, 
    vw2.strFullName, 
    vw2.strAddress1, 
    vw2.strCity 
FROM tblMatches M 
JOIN vwImportNameAddress vw1 ON vw1.NameAddressKey = M.Record1 
JOIN vwImportNameAddress vw2 ON vw2.DetailAddressKey = M.Record2 
+1

쿼리와 뷰 정의를 게시 할 수 있습니까? –

+1

보기 사용이 끔찍합니다. 지원되는 테이블에서 [UPDATE STATISTICS] (http://msdn.microsoft.com/en-us/library/ms187348.aspx)를 시도해보십시오. 그러나 실제로 데이터 모델을 변경해야한다고 생각합니다. 더 나은 ... –

+0

보기는 조인 된 테이블에 고유 한 키가 필요한 타사 응용 프로그램에 필요합니다. 결과를 보관 테이블에 채우고 앱에 전달하는 것이 더 나을 것입니다.하지만 SQL이 왜 비참하게 실패하는지에 대해 더 관심이 있습니다. 함수, 여러 개의 큰 조인 등을 사용하고 있습니까? – Brian

답변

1

당신이 이미 설명에 매우 가깝게 보입니다. 이 비 스 SARGable 술어의 조인 조건을 만들어

...

뷰는 여러 오히려 큰 테이블로 구성, 그리고 id 필드는 해당 ID의 문자열 연결이다 : 그것은 이것 때문에이다 SQL Server가 기본 테이블의 모든 인덱스를 사용하지 못하게합니다. 따라서 엔진은 각 조인 (모든 경우에 2 개)에 대해 모든 기본 테이블을 전체적으로 검사해야합니다.

아마도 각 테이블마다 하나씩 조인 수를 곱한 여러 가지 전체 테이블 검색을 피하기 위해 SQL Server는 이후에 단순히 카톤 제품과 필터를 사용하는 것이 더 빠르다고 판단했습니다 (따라서 " 조인 술어 없음 "경고). FORCE ORDER을 사용하면 처음에 요청한 모든 전체 스캔 및 중첩 루프를 정교하게 수행합니다.

나는이 뷰가 문제가되는 데이터 모델의 근저에 있다는 의견에 동의하지만, 발견 한 단기적인 해결 방법은 뷰에서 계산 된 ID 열을 인덱싱하는 것입니다 (분명히) 실제 생성 된 ID의 해시가 있기 때문에 다시 sargable로 만듭니다.


편집 : 나는 또한 처음에이 놓친 읽기를 통해 :

WHERE dbo.fnDatesAreOverlapping(N.dtmValidStartDate,N.dtmValidEndDate,A.dtmValidStartDate,A.dtmValidEndDate) = 1 

이 다시, 성능 저하로 이어질 것입니다 비 스 SARGable 술어입니다. UDF의 모든 열을 Y 꾸는 것은이 동작을 유발합니다. 뷰를 인덱싱하면 쿼리가 구체화되어 쿼리 속도에 영향을 줄 수 있습니다. 인덱스가 없으면이 술어는 매번 평가되어야하며 복합 ID가 없더라도 기본 테이블에서 전체 스캔을 강제 실행해야합니다.

+0

I 그러나 궁금한 점은 SQL Server가 noexpand 힌트없이 인덱스를 제대로 활용하지 못하는 이유입니다. 매우 큰 데이터 집합에 대해 매우 나쁜 쿼리를 처리 할 수 ​​없기 때문에 예상치 못한 수치를 채워야하는 것처럼 보입니다. 마찬가지로 계획 그 자체. – Brian

+0

@ 브라이언 : 반대의 증거가없는 한, 나는 아마 오래된 통계를 비난 할 것입니다. 'NOEXPAND'를 사용해야 할 경우 옵티마이 저가 뷰에서 인덱스를 사용하는 대신 기본 테이블을 쿼리하는 것이 더 쌀 것이라고 생각합니다. 내가 생각할 수있는 유일한 이유는 (a) 최종 쿼리 예제에 표시되지 않는 더 많은 용인 할 수없는 조건이거나 (b) 옵티마이 저가 기본 테이블 쿼리가 실제보다 훨씬 저렴하다고 생각하는 것입니다 (이는 일반적으로 나쁜 통계로 인한 것입니다). 술어가 괜찮다면,'sp_updatestats'를 시도하십시오. – Aaronaught

+0

아 - 그것은 또한 비 커버 인덱스의 결과 일 수 있습니다. 구체화 된 뷰가 실제로 필요한 모든 출력 컬럼을 가지고 있지 않다면 뷰를 모든 단일 기본 테이블에 효과적으로 결합시켜야하므로 매우 비싸다고 볼 수 있습니다. 인덱스에'INCLUDE'을 올바르게 사용하고 있는지 확인하십시오. – Aaronaught

1
그것은 당신의 기능을 분석 할 것이다

(fnGetCombinedTwoPartKey) 결과 컬럼을 작성하기 위해 어떤 컬럼이 페치되는지 판별하십시오. 모든 열이 필요하다고 가정 할 수는 없습니다. 인덱스가 인덱스를 덮고 있다면 예상치가 잘못 될 것입니다.