DELETE 는 지우는 행마다 되돌리기 위한 언두 정보와 복구를 위한 로그를 남깁니다. 지울 행이 많을수록 이 기록이 커지고, 커밋하기 전까지 그 행들의 잠금이 유지됩니다. 실패하거나 취소하면 남긴 기록을 되돌려야 하므로 롤백도 오래 걸립니다.
| 문제 | 한 번에 큰 DELETE | 나눠서 삭제 |
|---|---|---|
| 언두·로그 | 전체 분량이 한꺼번에 쌓임 | 청크 크기만큼만 쌓이고 커밋 뒤 정리됨 |
| 잠금 | 끝날 때까지 전체 행 잠금 | 청크 동안만 잠금 (대용량 07 락) |
| 실패 시 | 전부 롤백, 오래 걸림 | 마지막 청크만 롤백, 앞은 남음 |
| 진행 확인 | 끝나야 알 수 있음 | 청크마다 남은 건수 확인 |
흐름은 대용량 06 대량 처리의 청크 처리와 같습니다. 기준일 이전 행 중 N건을 지우고 커밋하고, 남은 대상이 0건이 될 때까지 되풀이합니다. 남은 대상이 청크 크기보다 적으면 있는 만큼만 지우고 끝납니다.
N건만 지우는 문법은 DB 마다 다릅니다.
| DB | N건만 삭제 |
|---|---|
| Oracle · Tibero | WHERE ROWNUM <= n, 또는 키 범위 |
| MySQL | DELETE ... LIMIT n (단일 표 DELETE 에서만) |
| MSSQL | DELETE TOP (n) |
| 표준 문법 | 서브쿼리에서 FETCH FIRST n ROWS ONLY (MySQL 불가) |
키 범위(id > a AND id <= b)로 나누면 DB 와 상관없이 같은 문장이고, 청크가 끝날 때 마지막 키를 기록하면 재시작도 쉽습니다.
핵심삭제 조건 컬럼(날짜)에는 인덱스가 있어야 합니다. 인덱스가 없으면 청크마다 표 전체를 훑어서, 청크가 100번이면 전체 읽기도 100번 일어납니다.
행을 지워도 그 행이 차지하던 공간은 운영체제에 바로 돌아가지 않고 표 안의 빈 공간으로 남습니다. 새 행이 들어오면 재사용하지만, 표가 더 이상 커지지 않는다면 그대로 남습니다. DB 별로 공간을 정리하는 방법이 다릅니다.
| DB | 삭제 뒤 상태 | 공간 정리 |
|---|---|---|
| Oracle | 최고 수위(HWM)가 그대로라 전체 읽기가 빈 블록까지 훑음 | SHRINK SPACE (10g 부터, ENABLE ROW MOVEMENT 필요) 또는 MOVE (인덱스 재생성 필요) |
| MySQL InnoDB | 파일 크기가 줄지 않음 | OPTIMIZE TABLE (표 재구성) |
| MSSQL | 빈 페이지가 남고 조각화 | 인덱스 REBUILD. 파일 축소(DBCC SHRINKFILE)는 조각화를 부르므로 신중히 |
정리 작업은 표를 다시 쓰거나 잠그는 무거운 작업이라 삭제와 별개로 점검 시간에 계획해서 합니다.
지운 데이터를 나중에 확인해야 하면 보관 표(log_archive)로 옮긴 뒤 지웁니다. 안전하게 하려면 세 가지를 지킵니다.
INSERT 와 DELETE 는 같은 키 집합에 같은 조건으로 실행합니다.INSERT 를 커밋하고 나서 DELETE 하면, 그 사이에 실패했을 때 같은 행이 양쪽에 남습니다. 반대로 DELETE 를 먼저 커밋하면 실패했을 때 행이 사라집니다. 실무 09 이관·검증의 대사 방식을 그대로 씁니다.
지울 행이 대부분이고 남길 행이 소수라면 지우는 것보다 남길 행만 새 표로 복사하는 쪽이 빠릅니다. 큰 삭제는 행마다 로그를 남기지만, 새 표에 넣는 일은 남길 행만 쓰기 때문입니다.
| 단계 | 내용 |
|---|---|
| 1 | 남길 행만 새 표로 복사 (CTAS 또는 CREATE 후 INSERT ... SELECT) |
| 2 | 새 표에 PK·인덱스·제약을 다시 만든다 |
| 3 | 이름 바꾸기: 원본을 옛 이름으로, 새 표를 원래 이름으로 |
| 4 | 건수 확인 후 옛 표 DROP |
주의할 점도 있습니다. CREATE TABLE AS SELECT 는 데이터만 복사하므로 인덱스·PK·FK·권한·트리거는 직접 다시 만들어야 합니다. 작업하는 동안 원본에 들어오는 쓰기를 막아야 하고, 그렇지 않으면 복사한 뒤 들어온 행이 바꿔치기와 함께 사라집니다. 옛 표를 참조하는 뷰·프로시저도 점검해야 합니다.
| 상황 | 방법 |
|---|---|
| 표 전체를 비운다 | TRUNCATE (FK 로 참조되는 표는 불가, Oracle·MySQL 은 롤백 불가, MSSQL 은 트랜잭션 안에서 가능) |
| 일부만 지우고 나머지가 훨씬 많다 | 나눠서 삭제 |
| 지울 양이 대부분이다 | 남길 행만 새 표로 옮기고 바꿔치기 |
| 날짜 기준으로 정기적으로 지운다 | 파티션으로 설계해서 조각을 떼어 냄 (대용량 05 파티션) |
| 지운 뒤에도 봐야 한다 | 보관 표로 이동 후 삭제 |