더 이상 사용하지 않는 데이터를 정리하여 성능과 용량을 최적화하는 작업입니다.
PostgreSQL에서는 데이터를 수정하거나 삭제할 때 파일을 즉시 지우지 않고 '더 이상 유효하지 않음'이라고 표시만 해두는 방식을 사용하는데, 이를 정리해주는 과정이 VACUUM입니다.
MVCC 때문입니다. MVCC란 multiversion concurrency control으로 과거의 스냅샷을 활용해 읽기와 쓰기가 싸우지 않고(락을 걸지 않고) 동시성을 관리해 성능을 높이는 방법을 의미합니다. (이전에는 2PL)
UPDATE/DELETE 시: 행(Row)을 진짜 지우는 게 아니라, 기존 데이터는 "죽은 상태(Dead Tuple)"로 두고 새로운 데이터를 추가합니다.
문제점: 이렇게 쌓인 죽은 데이터들이 공간만 차지하고 DB 성능을 갉아먹게 되는데, 이를 비대화(Bloat) 현상이라고 부릅니다.
VACUUM 명령어를 실행하면 다음과 같은 세 가지 중요한 작업이 일어납니다.
공간 재활용: 죽은 튜플(Dead Tuple)이 차지하던 공간을 '새로운 데이터를 쓸 수 있는 공간'으로 마킹합니다.
통계 정보 업데이트: ANALYZE와 함께 실행되어 쿼리 실행 계획을 짜는 Planner에게 최신 데이터 분포 정보를 제공합니다.
트랜잭션 ID 겹침(Wraparound) 방지: Postgres의 트랜잭션 ID는 유한합니다. 이를 주기적으로 정리해주지 않으면 어느 순간 DB가 멈출 수 있는데, 이를 방지하는 필수 작업입니다.
Autovacuum: 알아서 정리를 해주긴 한다. 단, 1분마다 용량이 넘어가면 정리를 하는 느낌
가장 많이 사용하는 조합은 VACUUM과 ANALYZE를 함께 쓰는 것입니다.
현재 DB의 모든 테이블 정리:
VACUUM;
특정 테이블만 정리:
VACUUM 테이블명;
정리 후 통계 정보까지 업데이트 (권장):
VACUUM ANALYZE 테이블명;
최신 버전의 PostgreSQL에서는 괄호()를 사용한 구문을 권장합니다.
진행 과정을 자세히 보기 (VERBOSE):
VACUUM (VERBOSE, ANALYZE) 테이블명;
디스크 용량을 실제로 반환하기 (FULL):
VACUUM (FULL, FREEZE, VERBOSE, ANALYZE) 테이블명;
주의: FULL은 테이블에 강력한 락(Lock)을 걸어서 작업 동안 해당 테이블을 읽거나 쓸 수 없습니다. 서비스 점검 시간 등에만 사용하세요.
명령어를 날리기 전에, "내 테이블에 청소가 얼마나 필요한가?"를 먼저 확인해 보는 것이 좋습니다.
죽은 데이터(Dead Tuples)가 얼마나 쌓였는지 확인:
SELECT
relname AS table_name,
n_dead_tup AS dead_tuples, -- 죽은 행 수
last_vacuum, -- 마지막 수동 VACUUM 날짜
last_autovacuum -- 마지막 자동 VACUUM 날짜
FROM pg_stat_all_tables
WHERE schemaname = 'public'
ORDER BY n_dead_tup DESC;