절없이 거대한 DELETE FROM <table>의 속도를 높이는 방법


37

SQL Server 2005 사용

where 절없이 거대한 DELETE FROM을 수행하고 있습니다. TRUNCATE를 사용할 수 없다는 것을 제외하고는 기본적으로 TRUNCATE TABLE 문과 동일합니다. 문제는 테이블이 거대하다는 것입니다-천만 행이며 완료하는 데 1 시간 이상이 걸립니다. 다음없이 빠르게 만들 수있는 방법이 있습니까?

  • 자르기 사용
  • 색인을 비활성화하거나 삭제 하시겠습니까?

t-log는 이미 별도의 디스크에 있습니다.

어떤 제안이라도 환영합니다!


2
이 작업을 많이하려면 테이블 분할
Gaius

1
테이블을 참조하는 FK 제약 조건이 있으므로 TRUNCATE를 사용할 수 없습니까?
Nick Chammas

답변:


39

할 수있는 일은 다음과 같이 일괄 삭제입니다.

SELECT 'Starting' --sets @@ROWCOUNT
WHILE @@ROWCOUNT <> 0
    DELETE TOP (xxx) MyTable

xxx가 50000 인 곳

매우 높은 비율의 행을 제거하려는 경우 수정 사항 ...

SELECT col1, col2, ... INTO #Holdingtable
           FROM MyTable WHERE ..some condition..

SELECT 'Starting' --sets @@ROWCOUNT
WHILE @@ROWCOUNT <> 0
    DELETE TOP (xxx) MyTable WHERE ...

INSERT MyTable (col1, col2, ...)
           SELECT col1, col2, ... FROM #Holdingtable

3
@tuseau : 오류가 발생하면 롤백 할 때마다 삭제시 약간의 로그 공간이 필요합니다. 50k 행 삭제는 10m 행 삭제보다 적은 리소스 / 공간을 사용합니다. 물론 로그 백업은 여전히 ​​실행되고 공간을 차지하지만 서버에서는 큰 것을 일괄 처리하는 것보다 많은 작은 배치가 더 쉽습니다.
gbn

1
고맙습니다, 일괄 삭제는 약간 도움이됩니다. 최상의 옵션이라고 생각합니다.
tuseau

2
@ Phil Helmer : 일괄 삭제가 트랜잭션에 있으면 사용중인 이득이 없습니다. 그렇지 않으면 각 로그 쓰기가 더 작아서 더 쉬운로드입니다
gbn

1
한 가지 추가 의견 : 일괄 삭제는 엄청난 도움이되며 1 시간 42 분에서 3 분으로 2 천만 행을 삭제합니다. 그러나 테이블에 클러스터형 인덱스가 있는지 확인하십시오! 힙인 경우 TOP 절은 실행 계획에서 정렬을 작성하여 개선을 무효화합니다. 나중에 명백해 보인다.
tuseau

2
@Noumenon : 그것은 @@ ROWCOUNT을 보장하는 것은 1
GBN

21

TOP 절을 사용하여이를 쉽게 수행 할 수 있습니다.

WHILE (1=1)
BEGIN
    DELETE TOP(1000) FROM table
    IF @@ROWCOUNT < 1 BREAK
END

중괄호는 코드를 포맷합니다
gbn

@gbn 그것은 너무입니다. 여기는 여전히 101 010입니다.
bernd_k

7

TRUNCATE를 사용할 수없는 경우 삭제 가능한 항목을 일괄 처리 할 수있는 제안에 동의하며 독창성에 대한 제안 삭제 / 생성 제안을 좋아하지만 귀하의 질문에 다음 의견이 궁금합니다.

기본적으로 TRUNCATE TABLE 문과 동일합니다. TRUNCATE 를 사용할 수 없다는 점을 제외하고

이 제한의 이유는 테이블을 직접 자르기 위해 부여 해야하는 보안 및 관련 테이블 이외의 테이블을자를 수 있다는 사실과 관련이 있다고 생각합니다.

이 경우 TRUNCATE TABLE을 사용하고 "EXECUTE AS"를 사용하는 저장 프로 시저를 만든 것이 테이블을 직접 자르는 데 필요한 보안 권한을 부여하는 대안으로 간주되는지 궁금합니다.

이 방법을 사용하면 회사가 db_ddladmin 역할에 계정을 추가 할 때 발생할 수있는 보안 문제를 해결하면서 필요한 속도를 얻을 수 있기를 바랍니다.

이 방법으로 저장 프로 시저를 사용하면 저장 프로 시저 자체를 잠 가서 특정 계정 만 사용할 수 있다는 이점이 있습니다.

어떤 이유로 든 이것이 허용 가능한 솔루션이 아니고이 테이블의 데이터를 제거해야 할 필요성이 하루 / 시간 등 한 번 수행되어야하는 경우 테이블을 자르기 위해 SQL 에이전트 작업을 작성하도록 요청합니다. 매일 예정된 시간에.

도움이 되었기를 바랍니다!


5

잘라내기를 제외하면 배치로만 삭제하면 도움이됩니다.

물론 모든 제약 조건과 인덱스를 사용하여 테이블을 삭제하고 다시 만들 수 있습니다. Management Studio에는 삭제 및 생성 할 테이블을 스크립팅 할 수있는 옵션이 있으므로 간단한 옵션이어야합니다. 그러나 이것은 DDL 작업을 수행 할 수있는 경우에만 가능합니다. 실제로는 옵션이 아닙니다.


응용 프로그램은 동시 작업을 위해 설계되었으므로 구조 (DDL)를 변경하고 자르기를 사용하는 것이 옵션이 아닙니다 ... 일괄 삭제가 가장 적합하다고 생각합니다. 그래도 고마워.
tuseau

1

이 질문은 매우 중요한 참고 자료 이므로이 코드를 게시하여 루프를 사용하여 삭제하고 루프 내에서 메시징을 진행하여 진행 상황을 추적하는 데 실제로 도움이되었습니다.

중복 질문 에서 쿼리가 수정됩니다 . 신용 할 @RLF 쿼리 기지.

CREATE TABLE #DelTest (ID INT IDENTITY, name NVARCHAR(128)); -- Build the test table
INSERT INTO #DelTest (name) SELECT name FROM sys.objects;  -- fill from system DB
SELECT COUNT(*) TableNamesContainingSys FROM #deltest WHERE name LIKE '%sys%'; -- check rowcount
go
DECLARE @HowMany INT;
DECLARE @RowsTouched INT;
DECLARE @TotalRowCount INT;
DECLARE @msg VARCHAR(100);
DECLARE @starttime DATETIME 
DECLARE @currenttime DATETIME 

SET @RowsTouched = 1; -- Needs to be >0 for loop to start
SET @TotalRowCount=0  -- Total rows deleted so far is 0
SET @HowMany = 5;     -- Variable to choose how many rows to delete per loop
SET @starttime=GETDATE()

WHILE @RowsTouched > 0
BEGIN
   DELETE TOP (@HowMany)
   FROM #DelTest 
   WHERE name LIKE '%sys%';

   SET @RowsTouched = @@ROWCOUNT; -- Rows deleted this loop
   SET @TotalRowCount = @TotalRowCount+@RowsTouched; -- Increment Total rows deleted count
   SET @currenttime = GETDATE();
   SELECT @msg='Deleted ' + CONVERT(VARCHAR(9),@TotalRowCount) + ' Records. Runtime so far is '+CONVERT(VARCHAR(30),DATEDIFF(MILLISECOND,@starttime,@currenttime))+' milliseconds.'
   RAISERROR(@msg, 0, 1) WITH NOWAIT;  -- Print message after every loop. Can't use the PRINT function as SQL buffers output in loops.  

END; 
SELECT COUNT(*) TableNamesContainingSys FROM #DelTest WHERE name LIKE '%sys%'; -- Check row count after loop finish
DROP TABLE #DelTest;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.