본문으로 건너뛰기
8.1 VACUUM과 autovacuum

8.1 VACUUM과 autovacuum

VACUUM은 MVCC가 남긴 dead tuple을 정리해 공간을 재사용 가능하게 만들고, XID wraparound을 막기 위해 tuple을 freeze하는 PostgreSQL 운영의 핵심 작업입니다. 수동 실행도 가능하지만 대부분의 시스템은 autovacuum이 알아서 돌게 둡니다. 둘의 동작과 운영 시 조절 포인트를 봅니다.

VACUUM의 일

작업목적
dead tuple 정리DELETE/UPDATE가 남긴 죽은 row를 공간 회수 후보로 표시. 다음 INSERT가 재사용
Free Space Map(FSM) 갱신어느 페이지에 빈 공간이 있는지 (1.5)
Visibility Map(VM) 갱신all-visible·all-frozen 비트 (4.3)
인덱스 정리죽은 tuple을 가리키던 인덱스 entry 제거
FREEZE오래된 XID를 FrozenXID로 바꿔 wraparound 안전
pg_class.relfrozenxid 갱신클러스터 wraparound 추적 (3.2)

dead tuple을 즉시 디스크에서 삭제하지는 않습니다. 공간을 재사용 가능 표시만 합니다. 실제 디스크 회수는 VACUUM FULL만 가능 (테이블 락 잡고 재구성, 운영 중 권장 안 함).

VACUUM의 종류

명령효과
VACUUM표준. dead 정리 + FSM/VM 갱신SHARE UPDATE EXCLUSIVE — SELECT/INSERT 가능
VACUUM FULL테이블 재구성 + 디스크 축소ACCESS EXCLUSIVE — 모든 쿼리 차단
VACUUM FREEZEaggressive freezeSHARE UPDATE EXCLUSIVE
VACUUM ANALYZEVACUUM + ANALYZE 동시동일
VACUUM (INDEX_CLEANUP off, ...)인덱스 정리 생략 (PG 12+)동일

PG 13+에서는 병렬 vacuum 가능 — 인덱스 정리를 병렬로 (PARALLEL N 옵션).

VACUUM (VERBOSE, ANALYZE, PARALLEL 4) orders;

autovacuum 동작

postmaster가 띄우는 autovacuum launcher가 주기적으로 깨어나 vacuum이 필요한 테이블을 찾고, autovacuum worker를 fork해 작업을 시킵니다.

트리거 조건

각 테이블별로 카운터를 봅니다.

카운터임계
n_dead_tupautovacuum_vacuum_threshold + autovacuum_vacuum_scale_factor × n_live_tup 초과
n_ins_since_vacuum (PG 13+)autovacuum_vacuum_insert_threshold + autovacuum_vacuum_insert_scale_factor × n_live_tup 초과
n_mod_since_analyzeautovacuum_analyze_threshold + autovacuum_analyze_scale_factor × n_live_tup 초과 (ANALYZE)
relfrozenxid 나이autovacuum_freeze_max_age(기본 2억) 초과 → aggressive

기본값:

파라미터기본
autovacuum_vacuum_threshold50
autovacuum_vacuum_scale_factor0.2 (20%)
autovacuum_vacuum_insert_threshold1000
autovacuum_vacuum_insert_scale_factor0.2
autovacuum_analyze_threshold50
autovacuum_analyze_scale_factor0.1
autovacuum_max_workers3
autovacuum_naptime1min

큰 테이블에서 0.2가 너무 큼

10M row 테이블이면 dead 2M가 쌓여야 vacuum이 돕니다. 그 사이 BLOAT이 자랍니다.

ALTER TABLE big_table SET (
  autovacuum_vacuum_scale_factor = 0.02,
  autovacuum_analyze_scale_factor = 0.02
);

큰 테이블은 항상 테이블별로 작은 값 권장합니다.

I/O 제한

autovacuum이 시스템에 부담을 주지 않도록 vacuum_cost 메커니즘으로 I/O를 제한합니다.

파라미터기본의미
autovacuum_vacuum_cost_delay2ms (PG 12+)비용 한도 도달 시 쉬는 시간
autovacuum_vacuum_cost_limit-1 (= vacuum_cost_limit 200)한 라운드의 비용 한도
vacuum_cost_page_hit1캐시 hit 페이지 비용
vacuum_cost_page_miss2cache miss 비용
vacuum_cost_page_dirty20dirty 만드는 페이지 비용

비용이 limit에 도달하면 delay만큼 쉬고 다시 시작합니다. 결과적으로 autovacuum이 전체 I/O의 일부만 사용합니다.

큰 시스템에서는 autovacuum_vacuum_cost_limit을 2000~10000 정도로 키워 더 빠르게 돌도록 합니다.

ALTER SYSTEM SET autovacuum_vacuum_cost_limit = 2000;
SELECT pg_reload_conf();

진단

-- 현재 돌고 있는 autovacuum
SELECT pid, datname, relid::regclass, query
  FROM pg_stat_activity
 WHERE backend_type = 'autovacuum worker';

-- dead tuple이 쌓이고 있는 테이블 상위
SELECT relname, n_live_tup, n_dead_tup,
       round(100.0 * n_dead_tup / nullif(n_live_tup, 0), 1) AS dead_pct,
       last_vacuum, last_autovacuum
  FROM pg_stat_user_tables
 ORDER BY n_dead_tup DESC
 LIMIT 10;

-- 진행률 (PG 12+)
SELECT * FROM pg_stat_progress_vacuum;

dead_pct가 20%+ 인 테이블이 자주 보이면 autovacuum이 못 따라오고 있다는 신호입니다.

XID wraparound 대비

SELECT datname,
       age(datfrozenxid) AS xid_age,
       pg_size_pretty(pg_database_size(datname)) AS size
  FROM pg_database
 ORDER BY xid_age DESC;

xid_age가 1.5억을 넘으면 autovacuum이 aggressive 모드(FREEZE)로 들어갑니다. 그래도 진행이 안 되면 17억 가까이서 read-only 강제 전환 위험합니다.

원인 — 거의 항상 긴 트랜잭션 또는 idle replication slot이 xmin horizon을 잡고 있어 vacuum이 무용합니다.

VACUUM이 안 되는 흔한 원인

원인확인
긴 트랜잭션pg_stat_activity.xact_start 오래된 row
잊혀진 prepared transactionpg_prepared_xacts
idle replication slotpg_replication_slotsxmin, catalog_xmin
autovacuum 비활성 또는 enabled = falseALTER TABLE ... SET (autovacuum_enabled = ...)
cost limit 너무 작음autovacuum이 느려서 못 따라옴

운영 권장

  1. autovacuum은 항상 켜 두기 — 끄는 건 거의 사고의 시작
  2. 큰 테이블은 scale_factor를 0.02~0.05로 별도 설정
  3. idle in transaction timeout 설정 (3.1) — vacuum 차단 방지
  4. pg_stat_progress_vacuum으로 진행률 추적
  5. VACUUM FULL은 운영 중 금지pg_repack 대신
  6. xid_age 알람 1.5억 임계 모니터링
autovacuum = off는 사고의 시작. 일시적 디스크 절약 같은 이유로 끄면 BLOAT이 폭증하고 XID wraparound 위험이 자랍니다. 만약 일시 정지가 필요해도 테이블 단위로만 + 명시적 복구 일정.

정리

  • VACUUM = dead 정리 + FSM/VM 갱신 + FREEZE
  • autovacuum이 표준입니다. 운영자가 수동 호출은 ETL 직후 정도
  • 큰 테이블은 scale_factor를 작게 (0.02~0.05)
  • 큰 시스템은 autovacuum_vacuum_cost_limit을 키워 throughput ↑
  • vacuum이 못 도는 원인은 거의 항상 긴 트랜잭션·잊혀진 prepared·idle slot
  • VACUUM FULL은 운영 중 금지 — pg_repack 사용

다음 절(8.2)에서는 통계 갱신 — ANALYZE — 의 동작과 전략을 봅니다.