100mm 레코드에서 JOIN으로 업데이트하면 어떻게 더 잘할 수 있습니까? (T-SQL에서)


11

실제로 단일 테이블에서 1 억 개의 레코드를 업데이트하여 열의 varchar 값을 단순히 ID로 바꾸어 테이블을 정규화해야합니다. ( "대체"라고 말하지만 실제로 다른 열에 ID를 쓰고 있습니다.)

내가 달성하려는 것은 데이터 세트를 정규화하는 것입니다. 아직 정규화되지 않은 데이터에는 색인이 없습니다. 내 생각은 원시 값에 대한 인덱스를 작성하지 않고 업데이트가 완료된 후 varchar 값을 tinyint 값으로 대체 할 외래 키를 인덱싱하기를 기다리는 것입니다.

UPDATE A
SET A.AutoClassID = B.AutoClassID
FROM AutoDataImportStaging.dbo.Automobile as A
JOIN AutoData.dbo.AutoClass as B on (A.AutoClassName = B.AutoClassName)

배경

  • Server 2008 R2에서 MSSQL 2008 R2 사용
  • 서버에 8GB RAM이 있습니다
  • 서버에는 하나의 RAID10, 7200 RPM SATA가 있습니다 (제작에는 데이터를 읽고 쓸 수는 없으며 최근의 HD 부족으로 인해 비용이 필요했습니다)
  • 서버에는 듀얼 쿼드 코어 Xeon CPU가 있습니다
  • 기계가 다른 작업을 수행하지 않습니다 (현재는 dev 전용 이며이 프로세스 만 해당)
  • 단순 로깅이 설정되어 있습니까 (?-그러나 롤백 할 수 있도록 여전히 로깅합니까?)
  • 이 쿼리는 가치있는 것에 대해 두 개의 다른 DB를 참조합니다.
  • 업데이트되는 테이블의 레코드 "폭"은 455 ​​바이트입니다.

실행 중 리소스

  • 물리적 RAM이 초과되었습니다
  • 디스크 I / O가 초과되었습니다
  • CPU가 거의 아무것도하지 않습니다 (초크 포인트는 I / O 임)
  • 실행 시간은 14 시간이고 계산되었습니다!

정규화 업데이트 후 열 (AutoClassName)을 삭제하더라도 원시 데이터에 대한 인덱스가 필요한 것 같습니다. 또한 JOIN 대신 한 번에 한 레코드 씩 테이블을 반복 해야하는지 궁금합니다. 이는 시작했을 때 어리석은 것처럼 보였지만 이제는 더 빨랐습니다.

남은 정규화 업데이트 (이와 유사한)에 대한 방법을 더 빨리 변경하려면 어떻게해야합니까?

답변:


7

이 작업을 단일 (매우 큰) 트랜잭션으로 수행하려고합니다. 대신 작은 배치로 업데이트를 수행하십시오.

또한 다음과 같은 이점이 있습니다.

  • AutoData.dbo.AutoClass.AutoClassName의 임시 색인
  • 더 많은 RAM. 많은 RAM이 있습니다.

1
+1 TOP조항을 사용한 배치 업데이트에 동의합니다 . 그게 내 접근 방식입니다.
토마스 스트링거

UPDATE TOP을 수행하면 WHERE 절이 필요합니다 (WHERE AutoClassID가 NULL 임)? WHERE 절이 새로운 성능 적중을 나타내지 않을 것입니다 (지금 수행하지 않는 테이블 스캔). 의심 할 여지없이 JOIN과 관련된 RAM 문제가 줄어들 것입니다.
Chris Adragna

제 답변은 기한이 지났지 만 제 경우 SET ROWCOUNT가 가장 효과적이었습니다.
Chris Adragna

10

나는 다른 접근법을 취할 것입니다.

기존 테이블을 업데이트하는 대신 필요한 테이블이있는 새 테이블을 작성하십시오.

이것은 거의 확실히 빠를 것입니다 :

SELECT DISTINCT
    AutoClassID,
    <Other fields>
INTO
    AutoDataImportStaging.dbo.Automobile
FROM
    AutoData.dbo.AutoClass

현재 작성된 것처럼 많은 논리적 작업이 발생합니다.

  • A.AutoClassName의 모든 값을 읽습니다.
  • B.AutoClassName의 모든 값을 읽습니다.
  • A와 B 값 비교
  • 일치하는 세트 중에서 B.AutoClassID의 모든 값을 읽으십시오.
  • 존재하는 인덱스를 통해 A.AutoClassId의 기존 값을 B.AutoClassId 값으로 업데이트

이것은 내가 가지고있는 디스크 I / O 문제를 감안할 때 멋지고 간단한 접근법처럼 들립니다. 너무 빨리 답변 해 주셔서 감사합니다.
Chris Adragna

1
로그 및 데이터 파일에 충분한 여유 공간이 있는지 다시 확인하는 것이 좋습니다. 파일이 자동으로 증가하면 성능이 급격히 향상됩니다. 사람들은 종종 큰 일회성 업데이트를 실행하고 로그 파일을 인식하지 않고 자동으로 자라는 것을 봅니다.
darin 해협

5

한 번에 한 행씩 테이블을 반복하면 빠르지 않습니다!

의심스럽고 확인 된대로, 이것은 하나의 디스크, 읽기, 쓰기, 트랜잭션 로그 및 (임의의) 임시 작업 공간이 모두 동일한 i / o를 위해 경쟁 할 것입니다.

단순 복구는 여전히 트랜잭션을 기록하지만 검사 점에 의해 로그가 지워집니다. 초기 로그 크기 및 자동 증가 설정으로 인해 일부 I / O 속도가 느려질 수 있습니다. 변경 사항을 수용하려면 트랜잭션 로그가 커져야합니다.

AutoClassName 필드를 인덱싱하려고 했습니까? 몇 가지 다른 AutoClass 값이 있습니까?

i / o의 한계에 따라 업데이트를 배치해야 할 수도 있습니다. 그래서 백만 업데이트, 체크 포인트, 반복 ....


15 개의 서로 다른 오토 클래스 값만 있습니다. 당신의 의견은 나의 많은 의심과 고통을 확인시켜줍니다. 답변 주셔서 감사합니다.
Chris Adragna

3

결합 필드에 대한 색인을 작성하십시오.

완료되면 언제든지 색인을 삭제할 수 있습니다.

인덱스가 업데이트 성능을 크게 향상시키지 않으면 매우 놀랐습니다.


인덱스가 향상 될 것이라고 확신합니다. 질문은 인덱스를 만드는 데 걸리는 시간보다 더 많이 개선되는지 여부입니다 (한 번만 사용). 아마 그렇습니다. :)
Chris Adragna

3

원하는 방식으로 내보내고 새 테이블을 만든 다음 다시 가져옵니다. 보너스로 기적이 발생하면 백업으로 데이터 사본을 갖게됩니다.

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