한양과학기술고등학교

에듀테크 프로젝트 대시보드

VACUUM 과 MVCC

MVCC dead tuple autovacuum bloat TOAST FREEZE

PostgreSQL 은 UPDATE/DELETE 시 기존 행을 지우지 않고 죽은 버전으로 남깁니다. 이걸 정리하는 게 VACUUM.

1. 왜 죽은 행이 생기나 (MVCC)

모든 행에는 xmin(만든 트랜잭션)·xmax(지운 트랜잭션) 이 있습니다. UPDATE 는 옛 행에 xmax 를 찍고 새 행을 추가 — 그래서 진행 중인 다른 트랜잭션이 옛 버전을 계속 볼 수 있습니다(읽기가 쓰기를 막지 않음).

VACUUM 이 하는 일
  • 어떤 트랜잭션도 더 볼 수 없는 죽은 행 공간을 재사용 가능 표시 (OS 로 반환은 아님)
  • visibility map 갱신 → Index Only Scan 가능하게
  • 트랜잭션 ID FREEZE → wraparound 방지

2. autovacuum

발동 조건 (기본값)
죽은 행 > autovacuum_vacuum_threshold(50) + 테이블행수 × scale_factor(0.2)
  → autovacuum 워커가 해당 테이블 VACUUM
-- 쓰기 많은 테이블은 더 자주 돌게 개별 조정
ALTER TABLE events SET (
    autovacuum_vacuum_scale_factor = 0.02,
    autovacuum_vacuum_cost_delay = 2
);

3. 상태 확인

SELECT relname, n_live_tup, n_dead_tup,
       last_autovacuum, last_autoanalyze
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC LIMIT 10;

VACUUM (VERBOSE, ANALYZE) events;   -- 수동 실행
ANALYZE events;                     -- 통계만 갱신 (플래너용)

4. bloat 와 VACUUM FULL

VACUUM FULL
  • 테이블을 통째로 다시 씀 → 공간을 OS 로 반환하지만 ACCESS EXCLUSIVE 락(서비스 중단)
  • 대안: pg_repack 확장 (락 최소화), 또는 애초에 autovacuum 튜닝

TOAST — 2KB 넘는 값(긴 text, jsonb)은 별도 TOAST 테이블에 압축 저장됩니다. pg_total_relation_size 에 포함됩니다.

"커넥션은 비싸다 — 요청마다 열지 말고 풀에서 빌려라"