[sql-server] 로그없이 SQL에서 테이블의 대용량 데이터를 삭제하는 방법은 무엇입니까?
큰 데이터 테이블이 있습니다. 이 테이블에는 1000 만 개의 레코드가 있습니다.
이 쿼리에 대한 가장 좋은 방법은 무엇입니까?
Delete LargeTable where readTime < dateadd(MONTH,-7,GETDATE())
답변
-
해당 테이블의 모든 행을 삭제하는 경우 가장 간단한 옵션은 테이블을 자르는 것입니다.
TRUNCATE TABLE LargeTable GO
Truncate table은 단순히 테이블을 비우고 WHERE 절을 사용하여 삭제되는 행을 제한 할 수 없으며 트리거가 실행되지 않습니다.
-
반면에 데이터의 80-90 % 이상을 삭제하는 경우 총 1 천 1 백만 행이 있고 1 천만 행을 삭제하려는 경우 다른 방법은이 1 백만 행을 삽입하는 것입니다 (보관하려는 레코드 )을 다른 스테이징 테이블에 추가합니다. 이 대형 테이블을 자르고이 100 만 행을 다시 삽입하십시오.
-
또는이 테이블을 기본 테이블로 사용하는 권한 /보기 또는 기타 개체가이 테이블을 삭제해도 영향을받지 않는 경우 상대적으로 적은 양의 행을 다른 테이블로 가져 와서이 테이블을 삭제하고 동일한 스키마를 가진 다른 테이블을 만들고 가져올 수 있습니다. 이 ex-Large 테이블에 행을 다시 넣습니다.
-
내가 생각할 수있는 마지막 옵션은 데이터베이스를 변경
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 백만 행을 삭제할 수있었습니다 . 여기 내 접근 방식이 있습니다.
당신이있는 경우 자동 증가 기본 키 이 테이블을, 당신은이 기본 키를 사용할 수있다.
-
readTime <dateadd (MONTH, -7, GETDATE ()) 인 대형 테이블의 기본 키 최소값을 가져옵니다. (readTime에 인덱스를 추가합니다. 아직없는 경우이 인덱스는 3 단계의 테이블과 함께 삭제됩니다.) 변수 ‘min_primary’에 저장할 수 있습니다.
-
기본 키> min_primary가있는 모든 행을 준비 테이블 (행 수가 크지 않은 경우 메모리 테이블)에 삽입합니다.
-
큰 테이블을 삭제하십시오.
-
테이블을 다시 만듭니다. 준비 테이블의 모든 행을 기본 테이블로 복사합니다.
-
스테이징 테이블을 삭제하십시오.