업데이트하는 행 수에 따라 완전히 다른 계획을 사용하는 T-SQL 쿼리


20

"TOP (X)"절이있는 SQL UPDATE 문이 있고 값을 업데이트하는 행에 약 40 억 개의 행이 있습니다. "TOP (10)"을 사용하면 거의 즉시 실행되는 하나의 실행 계획이 있지만 "TOP (50)"이상을 사용하는 경우 쿼리는 (적어도 내가 기다리는 동안은 아님) 끝나지 않습니다. 완전히 다른 실행 계획을 사용합니다. 더 작은 쿼리는 한 쌍의 인덱스 탐색과 중첩 루프 조인으로 매우 간단한 계획을 사용합니다. 여기서 UPDATE 문의 TOP 절에 다른 수의 행이있는 동일한 쿼리는 두 개의 다른 인덱스 탐색을 포함하는 계획을 사용합니다. , 테이블 스풀, 병렬 처리 및 기타 여러 복잡성.

"OPTION (USE PLAN ...)"을 사용하여 더 작은 쿼리로 생성 된 실행 계획을 사용하도록 강요했습니다.이 작업을 수행하면 몇 초 안에 최대 100,000 개의 행을 업데이트 할 수 있습니다. 쿼리 계획은 좋지만 SQL Server는 적은 수의 행만 포함 된 경우에만 해당 계획을 자체적으로 선택합니다. 업데이트에 상당히 많은 행 수가 있으면 차선책이됩니다.

나는 병렬 처리가 책임을 져야한다고 생각했기 때문에 MAXDOP 1쿼리를 설정 했지만 아무런 효과가 없었습니다. 나는 또한 sp_updatestats오늘 아침에 그 원인이 아닌 것을 보장하기 위해 달렸다 .

두 가지 실행 계획을 첨부했습니다. 더 짧은 계획도 더 빠릅니다. 또한 문제의 쿼리가 있습니다 (작은 행 수와 작은 행 수의 경우 포함 된 SELECT가 빠르다는 것을 주목할 가치가 있습니다).

    update top (10000) FactSubscriberUsage3
               set AccountID = sma.CustomerID
    --select top 50 f.AccountID, sma.CustomerID
      from FactSubscriberUsage3 f
      join dimTime t
        on f.TimeID = t.TimeID
      join #mac sma
        on f.macid = sma.macid
       and t.TimeValue between sma.StartDate and sma.enddate 
     where f.AccountID = 0 --There's a filtered index on the table for this

빠른 계획은 다음과 같습니다 . 빠른 실행 계획

그리고 여기에 느린 것이 있습니다 : 느린 실행 계획

쿼리를 설정하는 방식이나 쿼리 엔진이 잘못된 선택을 할 수있는 실행 계획에 명백한 것이 있습니까? 필요한 경우 관련된 테이블 정의와 이에 정의 된 인덱스도 포함시킬 수 있습니다.

통계 전용 버전의 데이터베이스 객체를 요청한 사람들에게 : 나는 당신이 그렇게 할 수 있다는 것을 몰랐지만, 그것은 완전하게 이해됩니다! 나는 통계 전용 데이터베이스에 대한 스크립트를 생성하여 다른 사람들이 스스로 실행 계획을 테스트 할 수 있었지만 필터링 된 인덱스에서 통계 / 히스토그램 생성 (스크립트의 구문 오류, 보인다)을 생성 할 수 있으므로 운이 없어. 필터를 제거하려고 시도했지만 쿼리 계획이 비슷했지만 정확히 같지는 않았으며 거위 추적에 아무도 보내지 않으려 고합니다.

업데이트 및보다 완전한 실행 계획 : 먼저, SQL Sentry의 Plan Explorer 는 놀라운 도구입니다. 나는이 사이트에서 다른 쿼리 계획 질문을 볼 때까지 그것이 존재한다는 것을 알지 못했고 쿼리가 어떻게 실행되는지에 대해 말할 것이 조금있었습니다. 문제를 해결하는 방법을 잘 모르겠지만 문제가 무엇인지 분명히 알았습니다.

다음은 10, 100 및 1000 개의 행에 대한 요약입니다. 1000 개의 행 쿼리가 다른 행과는 거리가 멀다는 것을 알 수 있습니다. 진술 요약

세 번째 쿼리에는 엄청나게 많은 읽기가 있으므로 완전히 다른 작업을 수행하고 있습니다. 행 개수와 함께 예상 실행 계획이 있습니다. 1000 행 예상 실행 계획 : 1000 행 예상 실행 계획

그리고 실행 계획의 실제 결과는 다음과 같습니다 (그러나 "완료하지 않음"으로, "시간 내에 완료"라는 의미 임). 1000 행 실제 실행 계획 1000 행 실제 실행 계획

내가 처음으로 알아 차린 것은 예상대로 dimTime 테이블에서 60K 행을 가져 오는 대신 실제로 B로 16 억을 끌어 당기는 것 입니다. 내 쿼리를 보면 dimTime 테이블에서 많은 행을 어떻게 철회하는지 잘 모르겠습니다. 내가 사용하는 BETWEEN 연산자는 팩트 테이블의 시간 레코드를 기반으로 #mac에서 올바른 레코드를 가져옵니다. 그러나 t.TimeValue (또는 t.TimeID)를 단일 값으로 필터링하는 WHERE 절에 행을 추가하면 몇 초 만에 100,000 행을 성공적으로 업데이트 할 수 있습니다. 그 결과, 포함 된 실행 계획에서 분명히 알 수 있듯이 시간표가 문제라는 것이 분명하지만이 문제를 해결하고 정확성을 유지하기 위해 조인 기준을 어떻게 변경할지 잘 모르겠습니다. . 이견있는 사람?

참고로 여기 100 행 업데이트 계획 (행 수 포함). 동일한 인덱스에 도달하고 여전히 많은 행을 가지고 있지만 동일한 크기의 문제는 발생하지 않습니다. 행 개수로 100 개의 행 실행 : 여기에 이미지 설명을 입력하십시오


GOTTA Be 통계입니다. sp_updatestatistics탁자 를 뛰었 어 ?
JNK 2016 년

@JNK : 처음에는 그렇게 생각했지만 변경없이 sp_updatestats를 이미 실행했습니다. 방금 다시 실행했으며 쿼리와 관련된 인덱스의 통계를 업데이트하지 않았습니다. 그래도 고마워!
SqlRyan 2016 년

두 번째는 좁은 (행당) 업데이트가 아니라 넓은 (인덱스 당) 업데이트 계획으로, 일부 가시적 인 복잡성을 설명합니다. 그러나 실제로 유일한 차이점은 조인 순서 from #mac sma join f on f.macid = sma.macid join dimTime t on f.TimeID = t.TimeID and t.TimeValue between sma.StartDate and sma.enddatefrom #mac join t on t.TimeValue between sma.StartDate and sma.enddate join f on f.TimeID = t.TimeID and f.macid = sma.macid
Martin Smith

여기 뭔가가 없습니다. 비싼 쿼리 계획조차도 행을 증분으로 생성해야합니다. A TOP 50는 여전히 빠르게 실행되어야합니다. XML 계획을 업로드 할 수 있습니까? 행 수를 봐야합니다. TOP 50maxdop 1을 사용하여 계획을 업데이트하고 게시하지 않고 선택으로 실행할 수 있습니까 ? (검색 공간을 단순화 / 비교하려는 시도).
usr

@usr joining on t.TimeValue between sma.StartDate and sma.enddate은 FactSubscriber에 대한 조인에서 나중에 필터링되어 훨씬 더 쓸모없는 행을 생성 할 수 있으므로 최종 결과로 끝나지 않습니다.
Martin Smith

답변:


3

dimTime의 인덱스가 변경되고 있습니다. 더 빠른 계획은 _dta 인덱스를 사용하는 것입니다. 먼저 sys.indexes에서 가상 인덱스로 표시되어 있지 않은지 확인하십시오.

@StartDate와 @enddate 사이에 다음과 같은 시작 / 종료 날짜를 제공하는 대신 #mac 테이블을 사용하여 필터링하여 일부 매개 변수화를 무시할 수 있다고 생각합니다. 임시 테이블을 제거하십시오.


dta 접두사가 붙은 인덱스는 이름을 사용자 지정하지 않고 DTA 권장 사항을 따라 만든 것처럼 보입니다. 가상 인덱스는 실제 실행 계획에 나타나지 않으며 문서화되지 않은 명령이 없으면 예상되지 않습니다. 두 번째 제안이 어떻게 작동하는지 잘 모르겠습니다. t.TimeValue between sma.StartDate and sma.enddate상관되어 있으므로 #temp테이블의 각 행마다 변경 될 수 있습니다 . OP가 무엇을 대체할까요?
Martin Smith

공정하게, 나는 임시 테이블에 충분히주의를 기울이지 않았다.
william_a_dba

1
그러나 가상 인덱스는 실제로 실행 계획을 망칠 수 있습니다. 가상적인 경우 삭제하고 다시 작성해야합니다. blogs.technet.com/b/anurag_sharma/archive/2008/04/15/…
william_a_dba 5

가상의 인덱스는 DTA가 완료되기 전에 완료 / 고정되지 않으면 남습니다. DTA에 딸꾹질이 있으면 수동으로 정리해야합니다.
william_a_dba

1
@william_a_dba-아, 나는 지금 당신이 무엇을 의미하는지 알 것입니다 (링크를 읽은 후). 쿼리가 계속 재 컴파일되었을 수는 없습니다. 흥미 롭습니다!
Martin Smith

1

계획의 행 수에 대한 자세한 정보가 없으면 예비 권장 사항은 쿼리에서 올바른 조인 순서를 정렬하고을 사용하여 강제하는 것 OPTION (FORCE ORDER)입니다. 첫 번째 계획의 가입 순서를 시행하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.