4 일이 지난 수백만 개의 레코드가있는 테이블 업데이트


12

현재 수백만 개의 레코드로 테이블을 업데이트하고 있으며 4 일이 지났으며 쿼리가 여전히 실행 중입니다.

쿼리가 실행 중임을 나타내는 활동 모니터를 확인했습니다.

이벤트 로그에는 전혀 오류가 없습니다.

현명한 성능 :

  • 디스크 A의 Tempdb (850GB 여유 공간)
  • 디스크 B의 데이터베이스 파일 (750GB 여유 공간)
  • 16GB 램

어떻게해야합니까?

쿼리

UPDATE
    dbo.table1
SET 
    costPercentage = ISNULL(t2.PaymentIndex, 1.0),
    t2.TopUp_Amt = (ISNULL(t2.PaymentIndex, 1.0) - 1.0)
    * ISNULL(dbo.table1.Initial_Tariff_Amt, 0.00),
    Total_Tariff_Inc_t2 = ISNULL(t2.PaymentIndex, 1.0)
    * ISNULL(dbo.table1.Initial_Tariff_Amt, 0.00)
FROM
    dbo.table2 t2
WHERE
    LEFT(dbo.test1.procodet, 3) = LEFT(t2.ProviderCode, 3) COLLATE database_default 

답변:


3

이 쿼리에는 처음에 발견되지 않은 흥미로운 세부 정보가 있습니다. Fabricio Araujo의 답변 덕분에 이제 볼 수 있습니다. 두 테이블에 액세스하고 있습니다. 이전에 이런 종류의 업데이트 문 사용법을 본 적이 없으며 사용하지 않는 것이 좋습니다. Fabricio의 답변에 따라보다 직관적 인 조인 구문을 사용하는 것이 좋습니다.

두 테이블 간의 조인으로 인해 많은 수의 행이 생성 될 수 있습니다. LEFT(col, 3)표현식이 중복 값을 생성하는 경우 발생할 수 있습니다 . 10 개의 복제본을 생성하면 조인 결과에 100000x100000 = 10000000000 개의 행이 생성됩니다.

나는 인덱싱이 여기서 역할을한다고 생각하지 않습니다. SQL Server는이 인덱싱되지 않은 조인을 해시 또는 병합 조인으로 해결할 수 있습니다. 4 일이 걸리지 않습니다.

다른 원인은 조인 입력 또는 출력의 카디널리티 과소 평가 일 수 있습니다. SQL Server가 루프 조인을 선택했을 수 있습니다.

이것은 여전히 ​​추측 이므로이 문제에 대해 밝힐 쿼리 계획을 게시하는 것이 좋습니다.


8

이 쿼리에서는 테이블의 모든 행을 스캔해야합니다.

  • procodet 또는 ProviderCode가 색인화되지 않은 것 같습니다.
  • 인덱스 된 경우에도 WHERE 술어에 대한 함수 인 LEFT가 있습니다.
  • 그리고 WHERE 술어의 함수 인 COLLATE도 있습니다.

"WHERE 술어의 함수"는 인덱스가 사용되지 않음을 의미합니다.

당신이 배치를하는 경우 다음 costPercentage에 인덱스를 필요로 (UPDATE TOP (10000)에 말을 ... 그리고 costPercentage는 NULL IS) 이 당신이 그것을 설정하는 가정합니다.

내가 볼 수있는 유일한 솔루션은

  • 기본 키를 기준으로 새 테이블을 일괄 적으로 채 웁니다.
  • LEFT 및 COLLATE 표현식을 숨기려면 색인이 생성되고 계산 된 열을 작성한 다음 업데이트를 실행하십시오.

@ gbn .. 감사합니다. 좋은 아이디어입니다 ..하지만 데이터가 수백만에 이르기 때문에이 프로세스는 시간이 걸릴 것입니다.
Lucky

1
"수백만"행을 스캔하는 데 4 일이 걸리는 이유는 무엇입니까? 행의 크기와 크기에 상관없이 4 일이 걸리지 않습니다. 문제의 근원은 여전히 ​​알려져 있지 않습니다.
usr

1
대용량 데이터를 정기적으로 다루는 경우 적절한 서버를 얻는 방법은 무엇입니까? SSD 등에 데이터를 넣습니다.
TomTom

1
@ 행운을 빕니다. 나는 대답을하고 있었다. 아직 찾지 못한 것이 있습니다. 자체 또는 하드웨어에 의한 쿼리가 아닙니다. 그것은 4 일 동안 지속되지 않을 것입니다.
usr

3
쿼리가 열의 3 자 부분을 다른 열의 3 자 부분에 연결하면 결과에 중복이 포함될 가능성이 높습니다. 이것은 단순히 수백만 행을 업데이트하는 것보다 훨씬 나쁩니다. 나는 그것이 수십억의 작업 테이블을 스캔하고 있다고 확신합니다.
datagod

4

먼저 쿼리를 다음과 같이 변경하십시오.

UPDATE t1
SET 
    costPercentage = ISNULL(t2.PaymentIndex, 1.0),
    t2.TopUp_Amt = (ISNULL(t2.PaymentIndex, 1.0) - 1.0)
    * ISNULL(dbo.table1.Initial_Tariff_Amt, 0.00),
    Total_Tariff_Inc_t2 = ISNULL(t2.PaymentIndex, 1.0)
    * ISNULL(dbo.table1.Initial_Tariff_Amt, 0.00)
FROM
  dbo.table1 t1
  inner join dbo.table2 t2
    on LEFT(t1.procodet, 3) = LEFT(t2.ProviderCode, 3) COLLATE database_default 

이 토론에서 Jeff Moden의 첫 번째 게시물 에서 알 수 있듯이 쿼리는 "할로윈 효과"에 대해 경고 한 것과 매우 유사합니다.

그런 다음 해당 LEFT 표현식을 색인화해야합니다. gbn의 대답은 그것을 수행하는 방법에 대한 포인터를 제공합니다.

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