2013-06-07 4 views
1

SQL Server 2008 R2에는 2 개의 테이블이 있습니다. 주기적으로 테이블 A에서 테이블 B로 레코드 일괄 처리를 삽입해야합니다. 삽입하는 동안 테이블 B는 여전히 & UPDATE를 선택할 수 있습니다. 현재, 우리는 INSERT..SELECT를 사용하여 테이블 A에서 테이블 B로 복사합니다. 그러나 삽입하는 동안 문제가 발생하는 경우가 있는데, 때로는 테이블 B 시간 초과에 대한 UPDATE 문이 발생합니다.테이블에서 다른 테이블로 대량 삽입

블로킹을 일으키지 않는 테이블에서 더 나은 대량 삽입 솔루션이 있습니까?

+0

루프에서 "update top (5000) ..."을 사용하는 것과 같이 더 작은 배치로 업데이트를 실행할 수 있습니다. – Stanley

+0

작은 배치로 삽입하는 것이 좋습니다. 좋은 생각입니다. 그러나 표 B에서 중복을 방지하기 위해 어떤 레코드가 복사되었는지 추적해야합니다. – kevin

답변

0

1 명령문이 더 이상 시간 초과되지 않도록 트랜잭션 시간 제한을 충분히 큰 값으로 설정하십시오.

2를 사용하여 커서를하며 일을하는이 방법을 시도 행

3에 의해 행 않습니다. 행 식별자 (예를 들어 IDENTITY)를, 최선의 해당 필드에서 PK 또는 INDEX를 가질 필요 :

SET NOCOUNT ON; 

CREATE TABLE #A(
    row_id INT IDENTITY(1,1) NOT NULL PRIMARY KEY, 
    data INT NOT NULL 
); 

CREATE TABLE #B(
    row_id INT NOT NULL PRIMARY KEY, 
    data INT NOT NULL 
); 

-- TRUNCATE TABLE #B; -- no truncate needed since you just want to add rows, not copy the whole table 

DECLARE @batch_size INT; 
SET @batch_size = 10000; 

DECLARE @from_row_id INT; 
DECLARE @to_row_id INT; 

-- You would use this to establish the first @from_row_id if you wanted to copy the whole table 
-- SELECT 
-- @from_row_id=ISNULL(MIN(row_id),-1) 
-- FROM 
-- #A AS a; 

SELECT 
    @from_row_id=ISNULL(MAX(row_id),-1) 
FROM 
    #B AS b; 

IF @from_row_id=-1 
    SELECT 
     @from_row_id=ISNULL(MIN(row_id),-1) 
    FROM 
     #A AS a; 
ELSE 
    SELECT 
     @from_row_id=ISNULL(MIN(row_id),-1) 
    FROM 
     #A AS a 
    WHERE 
     row_id>@from_row_id; 

WHILE @from_row_id>=0 
BEGIN 
    SELECT 
     @to_row_id=ISNULL(MAX(row_id),-1) 
    FROM 
     (
      SELECT TOP(@batch_size) 
       row_id 
      FROM 
       #A AS a 
      WHERE 
       row_id>[email protected]_row_id 
     ) AS row_ids 

    IF @to_row_id=-1 
    BEGIN 
     INSERT 
      #B 
     SELECT 
      * 
     FROM 
      #A AS a 
     WHERE 
      row_id>[email protected]_row_id; 

     BREAK; 
    END 
    ELSE 
     INSERT 
      #B 
     SELECT 
      * 
     FROM 
      #A AS a 
     WHERE 
      row_id BETWEEN @from_row_id AND @to_row_id; 

    SELECT 
     @from_row_id=ISNULL(MIN(row_id),-1) 
    FROM 
     #A AS a 
    WHERE 
     row_id>@to_row_id; 
END 

DROP TABLE #B; 
DROP TABLE #A; 
+0

감사합니다. 옵션 2 & 3을 테스트해야합니다. 전체 배치를 삽입하는 데 걸리는 시간 VS 허용되는 차단 기간. – kevin

+0

@kevin 옵션 2 전에 커서를 사용하면 옵션 3 이전에 커서를 사용하는 것이 효율적이지 않을 것입니다. 옵션 3과 같이 대량으로 삽입하는 대신 행을 복사하는 것이 일반적입니다. 스크립트가 유용하다고 생각되면 upvote 및/또는 "솔루션"표시를 확인하십시오. –

0

그들은 가장 확실한 해결책은 스탠리가 제안 작은 배치를 사용하는 것입니다. 이 옵션이 실제로 없다면 '(transaction level) snapshot isolation'을 탐색 할 수 있습니다.

+0

예. 지금까지 Stanley의 제안과 TT의 Option 3이 가장 효과적입니다. – kevin

관련 문제