"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 행 실제 실행 계획
내가 처음으로 알아 차린 것은 예상대로 dimTime 테이블에서 60K 행을 가져 오는 대신 실제로 B로 16 억을 끌어 당기는 것 입니다. 내 쿼리를 보면 dimTime 테이블에서 많은 행을 어떻게 철회하는지 잘 모르겠습니다. 내가 사용하는 BETWEEN 연산자는 팩트 테이블의 시간 레코드를 기반으로 #mac에서 올바른 레코드를 가져옵니다. 그러나 t.TimeValue (또는 t.TimeID)를 단일 값으로 필터링하는 WHERE 절에 행을 추가하면 몇 초 만에 100,000 행을 성공적으로 업데이트 할 수 있습니다. 그 결과, 포함 된 실행 계획에서 분명히 알 수 있듯이 시간표가 문제라는 것이 분명하지만이 문제를 해결하고 정확성을 유지하기 위해 조인 기준을 어떻게 변경할지 잘 모르겠습니다. . 이견있는 사람?
참고로 여기 100 행 업데이트 계획 (행 수 포함). 동일한 인덱스에 도달하고 여전히 많은 행을 가지고 있지만 동일한 크기의 문제는 발생하지 않습니다. 행 개수로 100 개의 행 실행 :
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.enddate
대from #mac join t on t.TimeValue between sma.StartDate and sma.enddate join f on f.TimeID = t.TimeID and f.macid = sma.macid
TOP 50
는 여전히 빠르게 실행되어야합니다. XML 계획을 업로드 할 수 있습니까? 행 수를 봐야합니다. TOP 50
maxdop 1을 사용하여 계획을 업데이트하고 게시하지 않고 선택으로 실행할 수 있습니까 ? (검색 공간을 단순화 / 비교하려는 시도).
t.TimeValue between sma.StartDate and sma.enddate
은 FactSubscriber에 대한 조인에서 나중에 필터링되어 훨씬 더 쓸모없는 행을 생성 할 수 있으므로 최종 결과로 끝나지 않습니다.
sp_updatestatistics
탁자 를 뛰었 어 ?