/* PostgreSQL Dead Tuple와 Vacuum 이야기 */
PostgreSQL을 쓰다 보면 디스크 사용량이 자꾸 늘어나거나, 쿼리가 점점 느려지는 경험을 한다.
그 주범 중 하나가 바로 **Dead Tuple(죽은 튜플)**이다.
오늘은 Dead Tuple이 어떻게 처리되는지, 그리고 이를 청소하는 Vacuum이 어떻게 동작하는지,
Lazy Vacuum, Auto Vacuum, Vacuum Full까지 깔끔하게 정리해본다.
/* Dead Tuple은 왜 생기나? */
PostgreSQL은 UPDATE나 DELETE 시 기존 데이터를 바로 덮어쓰지 않는다.
대신 MVCC(Multi-Version Concurrency Control)라는 방식으로 새 버전을 만든다.
UPDATE users SET name = 'Ewan' WHERE id = 1;
- 기존 튜플은 Dead Tuple이 된다. (다른 트랜잭션이 여전히 참조할 수도 있음)
- 새로운 튜플이 페이지에 추가된다.
이렇게 되면 테이블 안에는 살아있는 튜플과 죽은 튜플이 섞여 있게 된다.
/* Dead Tuple이 지나가는 길: FSM과 VM */
Dead Tuple은 그냥 버려지는 게 아니다.
PostgreSQL은 이를 추적하고 재활용하기 위해 FSM(Free Space Map)과 VM(Visibility Map)을 사용한다.
- FSM (Free Space Map)
→ 페이지 안에 얼마나 빈 공간이 있는지 저장.
→ 새로운 데이터가 들어올 때 "여기 빈자리 있어!" 하고 알려준다. - VM (Visibility Map)
→ 페이지의 모든 튜플이 visible(다른 트랜잭션에서 볼 수 있음) 상태인지 표시.
→ Vacuum이 "이 페이지는 건너뛰어도 된다"는 판단을 할 수 있게 해준다.
Dead Tuple이 생기면 FSM/VM에 표시가 되고, 다음 Vacuum 때 처리된다.
/* Lazy Vacuum: 페이지 내부 재활용 */
Lazy Vacuum은 말 그대로 “게으르게” 처리하는 방식이다.
- Dead Tuple이 있는 페이지를 찾아서
- 해당 공간을 다시 쓸 수 있게 마킹만 한다.
- 실제 디스크 파일 크기는 줄이지 않는다.
즉, 페이지 내부에서만 공간이 재활용된다.
이 방식의 장점은 빠르고 락을 최소화한다는 점이다.
단점은 디스크 파일 자체가 줄어들지 않기 때문에, 파일이 비대해진 상태라면 효과가 제한적이다.
/* Auto Vacuum: 알아서 청소부 */
매번 사람이 수동으로 VACUUM 치는 건 귀찮다.
그래서 PostgreSQL은 Auto Vacuum이라는 청소부를 내장하고 있다.
- 일정 기준(Dead Tuple 비율, 변경 횟수 등)을 초과하면 자동 실행
- Lazy Vacuum 방식으로 동작
- 트랜잭션 ID wraparound 방지도 함께 수행
- PostgreSQL에서 트랜잭션 ID(XID)가 21억 개 정도를 찍고 나면 다시 0부터 돌아오는 현상.
Auto Vacuum은 서비스 운영 중에 꾸준히 청소를 해주지만, 부하가 높은 시간대에는 약간의 성능 저하가 생길 수 있다.
/* 흐름 정리 */
Dead Tuple의 여정은 이렇게 된다.
UPDATE/DELETE
↓
Dead Tuple 생성
↓
FSM/VM에 표시
↓
Lazy Vacuum or Auto Vacuum → 페이지 내부 재활용
↓
(필요 시) Vacuum Full → 디스크 파일에서 완전 삭제
/* 마무리 */
PostgreSQL에서 Vacuum은 단순한 청소가 아니라 성능 유지와 데이터 무결성 보장을 위한 핵심 작업이다.
Auto Vacuum으로 평소 관리를 하고, 디스크를 줄여야 할 땐 Vacuum Full을 쓰면 된다.
다만, Vacuum을 무시하고 오래 방치하면 Dead Tuple이 쌓여서 쿼리 성능 저하 + 디스크 폭발이 발생할 수 있다.
결국 PostgreSQL에서의 성능 최적화는 청소 습관에서 시작된다고 봐도 과언이 아니다.
'데이터베이스' 카테고리의 다른 글
[Postgresql] Scan과 Join (2) | 2025.08.13 |
---|---|
[Postgresql] Lock 락 (5) | 2025.08.13 |
[Postgresql] 튜플 버전 (0) | 2025.07.22 |
[Postgresql] MVCC (다중 버전 동시성 제어) (0) | 2025.04.15 |
[Postgresql] 아키텍처 (0) | 2025.03.30 |