2009-04-15 5 views
26

20 개가 넘는 인덱스가있는 테이블에 수백만 개의 레코드를 삽입하려고합니다. 많은 인덱스가있는 테이블에 대해 느린 대량 삽입

가 마지막으로 실행에서는이 100.000 행 당 4 개 이상의 시간이 걸렸다, 쿼리가 3.5 일 이후에 취소 ...

는이 속도를하는 방법에 대한 제안이 있습니까.

는 (나는 원인으로 많은 인덱스를 의심 당신도 그렇게 생각한다면, 어떻게 자동으로 작동하기 전에 인덱스를 삭제할 수 있습니다, 다음 나중에 다시 같은 인덱스를 만들 수 있습니다.?)

추가 정보 :

  • 인덱스가 사용하는 공간은 데이터 만 사용하는 공간의 약 4 배입니다.
  • 삽입은 100.000 행당 트랜잭션으로 래핑됩니다. 상태에 대한

업데이트 :

가 허용 된 대답은 훨씬 더 빨리 그것을 만드는 저를 도왔다.

답변

41

인덱스를 사용하거나 사용하지 않도록 설정할 수 있습니다. 인덱스를 비활성화하면 인덱스를 다시 활성화 할 때만 발견되는 원치 않는 부작용 (예 : 중복 된 기본 키나 고유 인덱스 등)이 발생할 수 있습니다.

--Disable Index 
ALTER INDEX [IXYourIndex] ON YourTable DISABLE 
GO 

--Enable Index 
ALTER INDEX [IXYourIndex] ON YourTable REBUILD 
GO 
+8

아마도 PK 색인을 사용하지 않으려는 것입니다 (클러스터 된 경우에는 사용하지 마십시오). – Richard

+0

네, 맞습니다. 그 점을 지적 해 주셔서 감사합니다. – Lucero

+2

@Lucero :이 답변을 주셔서 감사합니다. 리차드의 의견에 따라 답변을 업데이트 할 수 있습니까? –

7

데이터웨어 하우스 작동처럼 들립니다. 삽입 전에 인덱스를 삭제하고 나중에 인덱스를 다시 작성하는 것이 일반적입니다.

인덱스를 다시 작성할 때 클러스터 된 인덱스를 먼저 작성한 다음 반대로 마지막으로 놓으십시오. 그들은 모두 fillfactor 100 %해야합니다. 인덱스가 아주 좋은 시작이 될 것입니다 않도록 다른 답변에서 언급 한 바와 같이

코드는이

if object_id('Index') is not null drop table IndexList 
select name into Index from dbo.sysindexes where id = object_id('Fact') 

if exists (select name from Index where name = 'id1') drop index Fact.id1 
if exists (select name from Index where name = 'id2') drop index Fact.id2   
if exists (select name from Index where name = 'id3') drop index Fact.id3 
. 
. 
BIG INSERT 

RECREATE THE INDEXES 
4

같은 것을해야한다. 100.000 행 당

4시간는 [...] 인서트는 100.000 행 당 트랜잭션에 싸여있다.

숫자를 줄이면 서버가 트랜잭션 중에 (너무 롤백 될 수 있음) 상태가 유지되어야하므로이 (색인과 함께) 데이터 추가가 매우 어렵다는 것을 의미합니다. 작업.

각 삽입 문을 고유 한 트랜잭션으로 묶지 않는 이유는 무엇입니까?

또한 사용중인 SQL의 특성을 살펴보고 명령문 (및 네트워크 왕복) 당 하나의 행을 추가합니까, 아니면 여러 개를 추가합니까?

+0

답변과 추가 질문에 감사드립니다. 대량 삽입은 저장 프로 시저에 대한 단일 호출로 발생합니다. –

+1

나는 단지 href = "# 751062"를 사용하는 다른 대답에 대한 링크가 페이지의 재 장전을 피한다고 생각한다. –

+0

@Ole : 링크 링크에 대한 아이디어를 주셔서 감사합니다 (회고록에서는 분명히 :-)). – Richard

3

색인을 비활성화 한 다음 다시 사용하도록 설정하는 것이 좋습니다. 왜냐하면이 접근 방식에 대한 나의 의구심은 다음과 같습니다.

(1) 응용 프로그램의 DB 사용자는 일반적으로 소유해서는 안되는 스키마 변경 권한이 필요합니다. (2) 선택한 삽입 방법 및/또는 색인 스키마가 처음에는 최적이되지 않을 수 있습니다. 그렇지 않으면 전체 인덱스 트리를 다시 작성한 다음 일정한 배치를 삽입하지 않아야합니다 (예 : 한 번에 하나의 삽입 문을 발행하는 클라이언트, 수천 개의 서버 라운드 트립이 발생하거나 클러스터 된 인덱스에 대한 선택의 여지가 없어 지속적인 인덱스 노드 분할이 발생합니다. 삽입은 클러스터 된 인덱스 노드 분할로 이어질되지 않도록

  • 증가 ADO.NET BatchSize에서
  • , 현명하게 목표 테이블의 클러스터 된 인덱스를 선택 : 내 제안은 다른 조금 보이는 이유

    . 일반적으로 ID 열은 좋은 선택입니다.

  • 클라이언트가 임시 힙 테이블에 먼저 삽입하도록하십시오 (힙 테이블에는 클러스터 된 인덱스가 없음). 다음, 문제가 하나의 큰 실제 목표 테이블에 모든 준비 테이블 데이터를 밀어 문을 "인서트로는-선택"
  • 대량 로그 복구 모델을 선택하여 SqlBulkCopy의
  • 감소 트랜잭션 로깅 적용을

당신에게 this article에 더 자세한 정보가 있습니다.