[PostgreSQL] VACUUM을 돌렸는데 디스크가 안 줄어드는 이유

VACUUM을 돌렸는데 디스크가 그대로라는 이야기를 종종 듣는다. 정상 동작이다. VACUUM은 공간을 운영체제에 돌려주는 명령이 아니다. 여기서부터 시작해서 VACUUM이 실제로 무엇을 하는지, bloat가 왜 쌓이고 어떻게 재는지까지 정리한다. 죽은 튜플은 어떻게 생기는가 PostgreSQL은 MVCC를 쓰기 때문에 UPDATE가 제자리 수정이 아니다. 기존 행을 고치는 게 아니라 새 버전을 하나 더 쓰고, 예전 버전에 “이 시점 이후로는 무효"라는 표시를 남긴다. DELETE도 마찬가지로 즉시 지우지 않고 무효 표시만 한다. 예전 버전을 바로 못 지우는 이유는 아직 그걸 봐야 하는 트랜잭션이 있을 수 있어서다. 먼저 시작된 트랜잭션에게는 여전히 그 버전이 유효한 데이터다. ...

9월 7, 2026 · Jun Kang

[PostgreSQL] 트랜잭션 ID는 42억 개인데 왜 20억마다 freeze가 도는가

시작은 사소한 의문이었다 PostgreSQL의 트랜잭션 ID(XID)는 32비트다. 그러면 2^32, 약 42억 9천만 개를 쓸 수 있다. 그런데 운영 문서를 읽다 보면 기준선이 자꾸 20억 근처에서 잡힌다. autovacuum_freeze_max_age의 상한도 20억이고, wraparound 경고도 20억 언저리에서 나온다. 공간은 42억인데 왜 절반만 쓰는 걸까. “안전 마진이겠지” 하고 넘어갔다가, 마진치고는 너무 정확히 절반이라는 게 계속 걸렸다. 그래서 물어봤고, 답을 듣고 나니 이건 마진이 아니라 구조적으로 그 이상 쓸 수 없는 값이었다. 순환 카운터에는 “절대적인 전후"가 없다 핵심은 XID가 단조 증가하는 값이 아니라 순환 카운터(circular counter) 라는 데 있다. 42억까지 올라가면 다시 0부터 시작한다. ...

7월 14, 2026 · Jun Kang