문제

나는 몇 개의 큰 테이블 (188m 및 144m 행)을 가지고 있지만보기에서 채워야하지만 각보기에는 수억 행이 포함되어 있습니다 (의사 차원 모델링 된 데이터를 평평한 형태로 함께 가져옵니다). 각 테이블의 키는 열의 50 개가 넘는 복합 바이트입니다. 데이터가 테이블에 있다면 항상 SP_RENAME을 사용하여 다른 새 테이블을 만드는 것에 대해 생각할 수 있지만 실제로는 옵션이 아닙니다.

단일 삽입 작업을 수행하면 프로세스는 엄청난 양의 트랜잭션 로그 공간을 사용하여 전형적인 트랜잭션 로그 공간을 사용하여 DBA와 함께 많은 번거 로움을 유발합니다. (그렇습니다. 이것은 아마도 DBA가 처리/디자인/건축가를 처리 해야하는 직업 일 것입니다)

SSIS를 사용하고 배치 커밋으로 대상 테이블로 데이터를 스트리밍 할 수 있습니다 (그러나 서버에서 SSIS 패키지를 실행할 수 없으므로 네트워크를 통해 데이터를 전송해야합니다).

행을 다른 배치에 배포하고 루프를 수행하기 위해 어떤 종류의 키를 사용하여 프로세스를 여러 삽입 작업으로 나누는 것 외에는 다른 것이 있습니까?

도움이 되었습니까?

해결책

데이터를 분할하고 커서 루프에 데이터를 삽입 할 수 있습니다. 그것은 SSIS Batchinserting과 거의 동일합니다. 그러나 서버에서 실행됩니다.

create cursor ....
select YEAR(DateCol), MONTH(DateCol) from whatever

while ....
    insert into yourtable(...)
    select * from whatever 
    where YEAR(DateCol) = year and MONTH(DateCol) = month
end

다른 팁

보기에는 고유 식별자 / 후보 키가 있습니까? 그렇다면 다음을 사용하여 해당 행을 작업 테이블로 선택할 수 있습니다.

SELECT key_columns INTO dbo.temp FROM dbo.HugeView;

(의미가 있다면,이 테이블을 단순 복구 모델을 사용 하여이 테이블을 다른 데이터베이스에 넣어 로그 활동이 기본 데이터베이스를 방해하는 것을 방지 할 수 있습니다. 이력서가 재개되기 전의 다른 데이터베이스는 문제가 주변에 디스크 공간이 부적절하다는 것입니다.)

그런 다음 한 번에 10,000 행을 삽입 한 다음 사이에 로그인을 백업 할 수 있습니다.

SET NOCOUNT ON;

DECLARE
    @batchsize INT,
    @ctr INT,
    @rc INT;

SELECT
    @batchsize = 10000,
    @ctr = 0;

WHILE 1 = 1
BEGIN
    WITH x AS
    (
        SELECT key_column, rn = ROW_NUMBER() OVER (ORDER BY key_column)
        FROM dbo.temp
    )
    INSERT dbo.PrimaryTable(a, b, c, etc.)
        SELECT v.a, v.b, v.c, etc.
        FROM x
        INNER JOIN dbo.HugeView AS v
        ON v.key_column = x.key_column
        WHERE x.rn > @batchsize * @ctr
        AND x.rn <= @batchsize * (@ctr + 1);

    IF @@ROWCOUNT = 0
        BREAK;

    BACKUP LOG PrimaryDB TO DISK = 'C:\db.bak' WITH INIT;

    SET @ctr = @ctr + 1;
END

그것은 내 머리 꼭대기에서 벗어나기 때문에 잘라/붙여 넣기/실행하지 말고 일반적인 아이디어가 있다고 생각합니다.

정기적 인 데이터베이스를 사용하고 로그 백업을받는 경우 로그 체인을 다시 시작하기 위해 가득 차게 될 것입니다.

나는 이것이 오래된 스레드라는 것을 알고 있지만 Arthur 's Cursor 솔루션의 일반 버전을 만들었습니다.

--Split a batch up into chunks using a cursor.
--This method can be used for most any large table with some modifications
--It could also be refined further with an @Day variable (for example)

DECLARE @Year INT
DECLARE @Month INT

DECLARE BatchingCursor CURSOR FOR
SELECT DISTINCT YEAR(<SomeDateField>),MONTH(<SomeDateField>)
FROM <Sometable>;


OPEN BatchingCursor;
FETCH NEXT FROM BatchingCursor INTO @Year, @Month;
WHILE @@FETCH_STATUS = 0
BEGIN

--All logic goes in here
--Any select statements from <Sometable> need to be suffixed with:
--WHERE Year(<SomeDateField>)=@Year AND Month(<SomeDateField>)=@Month   


  FETCH NEXT FROM BatchingCursor INTO @Year, @Month;
END;
CLOSE BatchingCursor;
DEALLOCATE BatchingCursor;
GO

이것은 우리의 큰 테이블의 부하에 대한 문제를 해결했습니다.

픽시 먼지는 없어요.

전송되는 실제 스키마에 대한 구체적인 내용을 알지 못하면 일반적인 솔루션은 정확히 설명하는 것과 같습니다. 처리를 여러 인서트로 나누고 키를 추적합니다. 이것은 일종의 의사 코드 t-sql입니다.

create table currentKeys (table sysname not null primary key, key sql_variant not null);
go

declare @keysInserted table (key sql_variant);
declare @key sql_variant;
begin transaction
do while (1=1)
begin
    select @key = key from currentKeys where table = '<target>';
    insert into <target> (...)
    output inserted.key into @keysInserted (key)
    select top (<batchsize>) ... from <source>
    where key > @key
    order by key;

    if (0 = @@rowcount)
       break; 

    update currentKeys 
    set key = (select max(key) from @keysInserted)
    where table = '<target>';
    commit;
    delete from @keysInserted;
    set @key = null;
    begin transaction;
end
commit

병렬 배치를 허용하고 키를 분할하려면 더욱 복잡해집니다.

BCP 명령을 사용하여 데이터를로드하고 배치 크기 매개 변수를 사용할 수 있습니다.

http://msdn.microsoft.com/en-us/library/ms162802.aspx

두 단계 프로세스

  • BCP는보기에서 텍스트 파일로의 데이터를 벗어납니다
  • BCP 텍스트 파일에서 배치 크기 매개 변수가있는 테이블로 데이터의 BCP

이것은 좋은 ol '을위한 직업처럼 보입니다. BCP.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top