모든 (1 천 2 백만) 레코드를 삭제 한 후 SQL Server "빈 테이블"이 느려 집니까?


27

약 150 개의 열이있는 SQL Server 2008 인스턴스가 있습니다. 이전에 약 1,200 만 개의 항목으로이 테이블을 채웠지만 이후 새 데이터 세트를 준비하기 위해 테이블을 지 웠습니다.

그러나 빈 테이블에 즉시 실행 된 한 번 같은 것을 명령 count(*)select top 1000에서가 SQL Management Studio지금 실행 옛날을.

SELECT COUNT(*) FROM TABLE_NAME 

0을 반환하는 데 11 분이 SELECT TOP 1000걸렸고 빈 테이블을 반환하는 데 거의 10 분이 걸렸습니다.

또한 하드 드라이브의 여유 공간이 문자 그대로 사라졌습니다 (100G에서 20G로 감소). 사이에 일어난 유일한 일은 내가 실행 한 단일 쿼리였습니다.

DELETE FROM TABLE_NAME

세계에서 무슨 일이 일어나고 있습니까?!?


5
데이터베이스는 어떤 복구 모델을 사용합니까? "Full"인 경우 SQL 인스턴스는 사용 가능한 공간이있는 위치에있을 수있는 모든 삭제 레코드를 저장합니다. 전체 복구가 필요한 경우 TRUNCATE TABLE대신을 사용 하는 것이 좋습니다 DELETE FROM.
Tullo_x86

2
열 150 개? 해당 테이블 가득 찼을 있습니다. 대부분의 튜플은 훨씬 작아야합니다. 그러나 전체 맥락 없이는 말할 수 없습니다.
Clockwork-Muse

답변:


42

TRUNCATE보다 훨씬 더 빠르거나 더 나은지 에 대해 이미 알고 DELETE있지만 여전히 해결해야 할 질문이 남아 있습니다.

완료SELECT 후 왜 느려 집니까?DELETE

때문이다 DELETE에만있다 고스트 행을. 테이블은 12M 행이 있었을 때만 큼 크지 않습니다. 행 수 (0)를 계산하려면 12M 행을 계산하는 데 시간이 걸립니다. 시간이 지나면 고스트 정리 프로세스에서 이러한 고스트 레코드를 가비지 수집하고 고스트 포함 된 페이지를 할당 해제 하면 SELECT 속도가 빨라집니다. 하지만 지금 Skipped Ghosted Records/secperfmon 을 체크인하면 아마도 급증 할 것입니다 SELECT COUNT(*). 테이블을 다시 작성하여 작업 속도를 높일 수도 있습니다 ALTER TABLE ... REBUILD..

TRUNCATE 유령을 남기지 않기 때문에이 문제를 처리했을 것입니다.

저장소 엔진 내부 : 고스트 정리 심층 도 참조하십시오 .


13

DELETEtransaction loglog sequence number (LSN)정보 를 유지 관리 할뿐 아니라 테이블의 행을 한 번에 하나씩 삭제하여의 각 행을 기록 합니다. 테이블에 거대한 데이터 (1 천 2 백만 레코드)가 있다고 언급 했으므로 삭제 후 하드 디스크 공간이 부족한 경우 데이터베이스 로그 파일의 크기를 확인하십시오. 아마 자랐을 것입니다.

더 나은 방법은 다음과 같습니다.

TRUNCATE TABLE_NAME

2
+1, Oracle DB와 동일합니다. 레코드를 기록하는 명령문을 사용하면 시간이 지남에 따라 데이터베이스 속도가 느려집니다.
Petro Semeniuk

@PetroSemeniuk Oracle에서 기억하는 것에서 delete는 highwater 마크 만 남겨두고 truncate는 highwater 마크를 재설정합니다. 전체 스캔이 필요한 작업은 최고 워터 마크까지 블록을 스캔한다고 생각합니다. 따라서 삭제하면 인덱스 작업에 도움이 될 수 있지만 스캔에는 도움이되지 않습니다. TRUNCATE가 올바르게 작동했습니다.
Glenn

3

(이것은 원래 @DaveE의 답변에 대한 주석 이었지만 시간이 오래 걸리기 때문에 자체 답변에 넣었습니다.)

TRUNCATE 기록 된 동작. 그렇지 않으면 ACID와 호환되지 않아야합니다. 그러나 차이 TRUNCATEDELETE:

  • 로그 공간 사용량 : TRUNCATE해제 된 페이지 / 연장자 * 만 DELETE기록하고 개별 행은 기록합니다.
  • 잠금 사용법 : 행 잠금을 사용 TRUNCATE하는 것과는 반대로 테이블 잠금 및 페이지 잠금을 사용하므로 일반적으로 잠금을 적게 DELETE사용합니다. **.
  • IDENTITYsequence : TRUNCATE테이블에서 ID 시퀀스를 재설정합니다 (있는 경우).

(* 익스텐트 = 8 페이지. TRUNCATE익스텐트가 모두 하나의 테이블에있는 경우 익스텐트를 기록 / 제거합니다. 그렇지 않으면 혼합 익스텐트에서 페이지를 기록 / 제거합니다.

** 이것의 한 가지 부작용 DELETE FROM TABLE은 작업이 독점 테이블 잠금을 얻을 수 있는지 여부에 따라 테이블에 빈 페이지가 할당 될 수 있다는 것입니다.)

따라서 (원래 질문으로 돌아가서), 테이블을 비우고 있지만 구조를 유지하려는 경우 (NB : 다른 테이블의 외래 키로 참조되는 테이블에서는 사용할 수 없음) TRUNCATE TABLE보다 결정적으로 좋습니다 .DELETE FROM TABLETRUNCATE

@Tullo의 의견에서 언급했듯이 데이터베이스의 복구 모델도 확인하십시오. 가득 차면 로그 백업을 시작하거나 복구 모델을 단순으로 변경해야합니다. 두 가지 중 하나를 수행하면 여유 공간을 모두 확보하기 위해 로그 파일을 일회용 작업 (NB : log file only ) 으로 축소 할 수 있습니다.

마지막으로 알아야 할 또 다른 사항은 테이블 통계입니다. 쿼리 최적화 프로그램이 이전 통계에 의해 트립되지 않도록 UPDATE STATISTICS <TABLENAME>' afterTRUNCATE /DELETE`를 실행하십시오 .


2

(참고 : DBA가 아닙니다.) DELETE는 기록 된 작업이며 사용 된 공간을 비우지 않습니다. '빈'테이블 스페이스에서 실행중인 공간 및 테이블 스캔을 차지하는 큰 트랜잭션 로그가있을 수 있습니다. 트랜잭션 로그를 지우고 데이터베이스를 축소해야한다고 생각합니다. 이 StackOverflow 기사 를 시작하십시오.

나중에이 작업을 수행하려면 TRUNCATE TABLE을 사용하십시오.

편집 : TRUNCATE가 기록되지 않는다는 내 설명이 잘못되었습니다. 제거되었습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.