내가 알 수있는 한, 일반 인서트를 최적화하는 것과 매우 유사한 방식으로 벌크 인서트를 최적화 할 수 있습니다. 일반적으로 간단한 삽입에 대한 쿼리 계획은 그다지 유익하지 않으므로 계획이없는 것에 대해 걱정하지 마십시오. 인서트를 최적화하는 몇 가지 방법을 살펴볼 것이지만 대부분 질문에 지정한 인서트에는 적용되지 않을 것입니다. 그러나 나중에 더 많은 양의 데이터를로드해야하는 경우 도움이 될 수 있습니다.
1. 클러스터링 키 순서로 데이터 삽입
SQL Server는 종종 클러스터 된 인덱스가있는 테이블에 데이터를 삽입하기 전에 데이터를 정렬합니다. 일부 테이블 및 응용 프로그램의 경우 플랫 파일의 데이터를 정렬하고 SQL Server에 데이터가 다음 ORDER
인수를 통해 정렬되었음을 알립니다 BULK INSERT
.
ORDER ({열 [ASC | DESC]} [, ... n])
데이터 파일의 데이터 정렬 방법을 지정합니다. 가져 오는 데이터가 테이블의 클러스터 된 인덱스 (있는 경우)에 따라 정렬되면 대량 가져 오기 성능이 향상됩니다.
IDENTITY
열을 클러스터 된 키로 사용하므로 걱정할 필요가 없습니다.
2. TABLOCK
가능하면 사용하십시오
테이블에 데이터를 삽입하는 세션이 하나만 보장되는 경우에 TABLOCK
인수를 지정할 수 있습니다 BULK INSERT
. 이는 잠금 경합을 줄이고 일부 시나리오에서 최소한의 로깅 으로 이어질 수 있습니다. 그러나 이미 데이터가 포함 된 클러스터형 인덱스가있는 테이블에 삽입하므로이 답변의 뒷부분에 나오는 추적 플래그 610없이 최소한의 로깅을 얻지 못합니다.
만약이 TABLOCK
있기 때문에, 수 없습니다 코드를 변경할 수 없습니다 , 모든 희망이 손실됩니다. 사용을 고려하십시오 sp_table_option
:
EXEC [sys].[sp_tableoption]
@TableNamePattern = N'dbo.BulkLoadTable' ,
@OptionName = 'table lock on bulk load' ,
@OptionValue = 'ON'
다른 옵션은 추적 플래그 715 를 활성화하는 것 입니다.
3. 적절한 배치 크기를 사용하십시오
배치 크기를 변경하여 인서트를 조정할 수있는 경우도 있습니다.
ROWS_PER_BATCH = rows_per_batch
데이터 파일의 대략적인 데이터 행 수를 나타냅니다.
기본적으로 데이터 파일의 모든 데이터는 단일 트랜잭션으로 서버에 전송되며 배치의 행 수는 쿼리 최적화 프로그램에 알려지지 않습니다. ROWS_PER_BATCH (값> 0)를 지정하면 서버는이 값을 사용하여 대량 가져 오기 작업을 최적화합니다. ROWS_PER_BATCH에 지정된 값은 실제 행 수와 대략 같아야합니다. 성능 고려 사항에 대한 자세한 내용은이 항목 뒷부분의 "설명"을 참조하십시오.
이 기사의 뒷부분에서 인용 한 내용은 다음과 같습니다.
단일 배치에서 플러시 할 페이지 수가 내부 임계 값을 초과하면 배치가 커밋 될 때 플러시 할 페이지를 식별하기 위해 버퍼 풀의 전체 스캔이 발생할 수 있습니다. 이 전체 스캔은 대량 가져 오기 성능을 저하시킬 수 있습니다. 큰 버퍼 풀이 느린 I / O 서브 시스템과 결합 될 때 내부 임계 값을 초과하는 경우가 발생합니다. 대형 머신에서 버퍼 오버 플로우를 방지하려면 대량 최적화를 제거하는 TABLOCK 힌트를 사용하지 않거나 대량 최적화를 유지하는 작은 배치 크기를 사용하십시오.
컴퓨터는 다양하기 때문에 데이터로드로 다양한 배치 크기를 테스트하여 가장 적합한 것이 무엇인지 찾아 보는 것이 좋습니다.
개인적으로 695 행을 모두 단일 배치로 삽입합니다. 배치 크기를 조정하면 많은 양의 데이터를 삽입 할 때 큰 차이를 만들 수 있습니다.
4. IDENTITY
컬럼 이 필요한지 확인하십시오
데이터 모델이나 요구 사항에 대해 아무것도 모르지만 IDENTITY
모든 테이블에 열을 추가하는 함정에 빠지지는 않습니다 . Aaron Bertrand는 이것에 관한 기사가있다 : 나쁜 습관을 걷어차 라 : 모든 테이블에 IDENTITY 열을두기 . 분명히하기 IDENTITY
위해이 테이블 에서 열을 제거해야한다고 말하지 않습니다 . 그러나 IDENTITY
열이 필요하지 않다고 판단한 경우 열을 제거하면 삽입 성능이 향상 될 수 있습니다.
5. 인덱스 또는 제약 조건 비활성화
이미 가지고있는 것과 비교하여 많은 양의 데이터를 테이블에로드하는 경우로드 전에 인덱스 또는 제약 조건을 비활성화하고로드 후 활성화하는 것이 더 빠를 수 있습니다. 많은 양의 데이터의 경우 일반적으로 데이터가 테이블에로드되는 대신 SQL Server에서 인덱스를 한 번에 모두 작성하는 것이 더 비효율적입니다. 11500 개의 행이있는 테이블에 695 개의 행을 삽입 한 것으로 보이므로이 기술을 권장하지 않습니다.
6. TF 610 고려
추적 플래그 610은 일부 추가 시나리오에서 최소 로깅을 허용합니다. IDENTITY
클러스터 키 가있는 테이블 의 경우 복구 모델이 단순하거나 대량 로그되어있는 한 새 데이터 페이지에 대해 최소한의 로깅을 얻을 수 있습니다. 이 기능은 일부 시스템의 성능을 저하시킬 수 있으므로 기본적으로 켜져 있지 않습니다. 이 추적 플래그를 활성화하기 전에 신중하게 테스트해야합니다. 권장되는 Microsoft 참조는 여전히 데이터로드 성능 안내서 인 것으로 보입니다.
추적 플래그 610에서 최소 로깅의 I / O 영향
최소한으로 기록 된 대량로드 트랜잭션을 커밋 할 때 커밋이 완료되기 전에로드 된 모든 페이지를 디스크로 플러시해야합니다. 이전 체크 포인트 작업으로 잡히지 않은 플러시 페이지는 많은 랜덤 I / O를 생성 할 수 있습니다. 이것을 완전히 기록 된 작업과 대조하면 로그 쓰기에 순차적 I / O가 생성되고 커밋 된 시간에로드 된 페이지를 디스크로 플러시 할 필요가 없습니다.
로드 시나리오가 검사 점 경계를 넘지 않는 btree에서 작은 삽입 작업이고 I / O 시스템이 느린 경우 최소 로깅을 사용하면 실제로 삽입 속도가 느려질 수 있습니다.
내가 알 수있는 한, 이것은 추적 플래그 610과 관련이 없으며 최소한의 로깅 자체와 관련이 있습니다. ROWS_PER_BATCH
튜닝에 대한 이전의 인용문도 이와 같은 개념을 취하고 있다고 생각합니다 .
결론적으로을 튜닝하기 위해 할 수있는 일은 많지 않을 것입니다 BULK INSERT
. 삽입물에서 관찰 한 읽기 횟수에 대해서는 걱정하지 않습니다. SQL Server는 데이터를 삽입 할 때마다 읽기를보고합니다. 다음과 같은 매우 간단한 것을 고려하십시오 INSERT
.
DROP TABLE IF EXISTS X_TABLE;
CREATE TABLE X_TABLE (
VAL VARCHAR(1000) NOT NULL
);
SET STATISTICS IO, TIME ON;
INSERT INTO X_TABLE WITH (TABLOCK)
SELECT REPLICATE('Z', 1000)
FROM dbo.GetNums(10000); -- generate 10000 rows
출력 SET STATISTICS IO, TIME ON
:
테이블 'X_TABLE'. 스캔 카운트 0, 논리적 읽기 11428
11428이 읽은 것으로보고되었지만 실행 가능한 정보는 아닙니다. 때때로 최소한의 로깅으로보고 된 읽기 수를 줄일 수 있지만 물론 그 차이를 성능 향상으로 직접 변환 할 수는 없습니다.