[sql-server] 로그없이 SQL에서 테이블의 대용량 데이터를 삭제하는 방법은 무엇입니까?

큰 데이터 테이블이 있습니다. 이 테이블에는 1000 만 개의 레코드가 있습니다.

이 쿼리에 대한 가장 좋은 방법은 무엇입니까?

   Delete LargeTable where readTime < dateadd(MONTH,-7,GETDATE())



답변

  1. 해당 테이블의 모든 행을 삭제하는 경우 가장 간단한 옵션은 테이블을 자르는 것입니다.

    TRUNCATE TABLE LargeTable
    GO

    Truncate table은 단순히 테이블을 비우고 WHERE 절을 사용하여 삭제되는 행을 제한 할 수 없으며 트리거가 실행되지 않습니다.

  2. 반면에 데이터의 80-90 % 이상을 삭제하는 경우 총 1 천 1 백만 행이 있고 1 천만 행을 삭제하려는 경우 다른 방법은이 1 백만 행을 삽입하는 것입니다 (보관하려는 레코드 )을 다른 스테이징 테이블에 추가합니다. 이 대형 테이블을 자르고이 100 만 행을 다시 삽입하십시오.

  3. 또는이 테이블을 기본 테이블로 사용하는 권한 /보기 또는 기타 개체가이 테이블을 삭제해도 영향을받지 않는 경우 상대적으로 적은 양의 행을 다른 테이블로 가져 와서이 테이블을 삭제하고 동일한 스키마를 가진 다른 테이블을 만들고 가져올 수 있습니다. 이 ex-Large 테이블에 행을 다시 넣습니다.

  4. 내가 생각할 수있는 마지막 옵션은 데이터베이스를 변경 Recovery Mode to SIMPLE한 다음 이와 같은 while 루프를 사용하여 더 작은 일괄 처리로 행을 삭제하는 것입니다.

    DECLARE @Deleted_Rows INT;
    SET @Deleted_Rows = 1;
    
    
    WHILE (@Deleted_Rows > 0)
      BEGIN
       -- Delete some small number of rows at a time
         DELETE TOP (10000)  LargeTable
         WHERE readTime < dateadd(MONTH,-7,GETDATE())
    
      SET @Deleted_Rows = @@ROWCOUNT;
    END

그리고 복구 모드를 다시 전체로 변경하는 것을 잊지 마십시오. 완전히 적용되도록하려면 백업을 수행해야한다고 생각합니다 (변경 또는 복구 모드).


답변

@ m-ali 대답은 맞지만 각 청크 후에 트랜잭션을 커밋하지 않고 체크 포인트를 수행하면 로그가 많이 커질 수 있음을 명심하십시오. 이것이 내가 그것을하는 방법 이며 성능 테스트 및 그래프와 함께 http://sqlperformance.com/2013/03/io-subsystem/chunk-deletes 를 참조로 사용합니다.

DECLARE @Deleted_Rows INT;
SET @Deleted_Rows = 1;


WHILE (@Deleted_Rows > 0)
  BEGIN

   BEGIN TRANSACTION

   -- Delete some small number of rows at a time
     DELETE TOP (10000)  LargeTable
     WHERE readTime < dateadd(MONTH,-7,GETDATE())

     SET @Deleted_Rows = @@ROWCOUNT;

   COMMIT TRANSACTION
   CHECKPOINT -- for simple recovery model
END


답변

GO + 동일한 쿼리를 실행하려는 횟수를 사용할 수도 있습니다.

DELETE TOP (10000)  [TARGETDATABASE].[SCHEMA].[TARGETTABLE]
WHERE readTime < dateadd(MONTH,-1,GETDATE());
-- how many times you want the query to repeat
GO 100


답변

@Francisco Goldenstein, 사소한 수정입니다. COMMIT는 변수를 설정 한 후에 사용해야합니다. 그렇지 않으면 WHILE이 한 번만 실행됩니다.

DECLARE @Deleted_Rows INT;
SET @Deleted_Rows = 1;

WHILE (@Deleted_Rows > 0)
BEGIN
    BEGIN TRANSACTION

    -- Delete some small number of rows at a time
    DELETE TOP (10000)  LargeTable
    WHERE readTime < dateadd(MONTH,-7,GETDATE())

    SET @Deleted_Rows = @@ROWCOUNT;

    COMMIT TRANSACTION
    CHECKPOINT -- for simple recovery model

END


답변

M.Ali 의이 변형은 저에게 잘 작동합니다. 일부를 삭제하고 로그를 지우고 반복합니다. 나는 로그가 커지고, 떨어지고, 다시 시작하는 것을보고 있습니다.

DECLARE @Deleted_Rows INT;
SET @Deleted_Rows = 1;
WHILE (@Deleted_Rows > 0)
  BEGIN
   -- Delete some small number of rows at a time
    delete top (100000) from InstallLog where DateTime between '2014-12-01' and '2015-02-01'
    SET @Deleted_Rows = @@ROWCOUNT;
    dbcc shrinkfile (MobiControlDB_log,0,truncateonly);
END


답변

파티셔닝을 구현할 의향이 있고 가능한 경우 런타임 오버 헤드가 거의없이 대량의 데이터를 제거하는 효과적인 기술입니다. 그러나 일회성 운동에는 비용 효율적이지 않습니다.


답변

2 천 1 백만 행의 테이블에서 몇 분 만에 1 천 9 백만 행을 삭제할 수있었습니다 . 여기 내 접근 방식이 있습니다.

당신이있는 경우 자동 증가 기본 키 이 테이블을, 당신은이 기본 키를 사용할 수있다.

  1. readTime <dateadd (MONTH, -7, GETDATE ()) 인 대형 테이블의 기본 키 최소값을 가져옵니다. (readTime에 인덱스를 추가합니다. 아직없는 경우이 인덱스는 3 단계의 테이블과 함께 삭제됩니다.) 변수 ‘min_primary’에 저장할 수 있습니다.

  2. 기본 키> min_primary가있는 모든 행을 준비 테이블 (행 수가 크지 않은 경우 메모리 테이블)에 삽입합니다.

  3. 큰 테이블을 삭제하십시오.

  4. 테이블을 다시 만듭니다. 준비 테이블의 모든 행을 기본 테이블로 복사합니다.

  5. 스테이징 테이블을 삭제하십시오.