오래된 데이터를 지웠는데 서버의 여유 디스크가 늘지 않았다면, 삭제 실패부터 단정할 필요는 없다. PostgreSQL에서는 행을 삭제하는 것, 그 자리를 다음 데이터에 재사용하는 것, 파일 크기를 줄여 운영체제에 공간을 돌려주는 것이 서로 다른 단계다.

2026년 10월 26일 조회한 PostgreSQL 공식 current 문서는 18 버전이었다. 이 글은 해당 문서를 기준으로 한 운영 점검 안내이며, 실제 계정 측정 결과나 특정 클라우드의 요금 견적이 아니다. 운영 중인 버전의 문서와 관리형 서비스 제한도 함께 확인해야 한다.

DELETE는 곧바로 파일 축소를 뜻하지 않는다

PostgreSQL의 MVCC에서는 다른 트랜잭션이 볼 수 있는 과거 행 버전을 즉시 없앨 수 없다. DELETE나 UPDATE 이후 더 이상 필요하지 않은 행 버전을 정리해 공간을 재사용하도록 만드는 작업이 VACUUM이다. 따라서 삭제한 행 수만으로 파일 감소량을 계산하면 안 된다. PostgreSQL 정기 VACUUM 설명

장기 트랜잭션 등으로 과거 버전이 여전히 필요하다면 기대한 만큼 정리되지 않을 수 있다. 먼저 삭제 작업의 완료 여부와 정리 가능 상태를 확인하자. 단지 디스크 수치가 같다는 이유로 같은 DELETE를 반복하는 것은 원인 진단을 대신하지 못한다.

100 GiB 중 60 GiB를 재사용해도 파일은 남을 수 있다

설명을 위한 가정이다. 테이블의 main fork가 100 GiB이고, 일반 VACUUM 이후 그 안의 60 GiB가 향후 같은 테이블의 데이터에 재사용 가능해졌다고 하자. 이 예시에서는 파일 끝 페이지 절단이 발생하지 않았고, 동시에 다른 쓰기도 없다고 가정한다.

  • 파일 크기: 그대로 100 GiB
  • 그 안의 재사용 가능 공간: 가정상 60 GiB
  • 이 작업으로 운영체제에 반환한 공간: 가정상 0 GiB

100 − 60 = 40 GiB라는 계산 결과는 이 가정에서 재사용 가능 영역을 뺀 나머지다. 실제 파일이 40 GiB로 줄었다거나 FULL 이후 정확히 40 GiB가 된다는 예측은 아니다. 행 개수의 60%를 삭제했다고 저장 바이트의 60%가 비는 것도 아니다. 인덱스·TOAST·기타 파일은 이 단순 예시에 포함하지 않았다.

재사용 가능한 공간은 같은 테이블의 향후 증가를 흡수하는 데 도움이 된다. 다만 행 크기와 페이지 배치 등이 달라질 수 있어 새 데이터 60 GiB를 반드시 추가 비용 없이 넣을 수 있다는 보장도 아니다.

가정상 main fork 100 GiB에서 내부 재사용 가능 공간은 60 GiB이지만 끝 페이지 절단이 없으면 운영체제 반환량은 0 GiB인 예시.
재사용과 반환은 다르다. 파일 크기: 100 GiB · 내부 재사용: 60 GiB · OS 반환: 0 GiB. 일반 VACUUM 후 main fork에 60 GiB가 재사용 가능해졌고 끝 페이지 절단과 동시 쓰기가 없다고 가정한다. 인덱스·TOAST 등은 제외했다. 실제 측정이나 FULL 후 파일 크기 예측이 아니다.

일반 VACUUM과 FULL은 잠금과 여유 공간 조건이 다르다

일반 VACUUM은 주로 기존 테이블 안의 공간 재사용을 위한 작업이다. 보통 읽기·쓰기와 함께 진행할 수 있지만 I/O 부하가 생길 수 있다. 또한 파일 끝에 완전히 빈 페이지가 있고 필요한 잠금을 얻을 수 있으면 일부 공간을 운영체제에 반환하는 예외가 있다. “일반 VACUUM은 파일을 절대 줄이지 않는다”는 설명도 정확하지 않다.

VACUUM FULL은 새 파일에 테이블을 다시 써서 공간을 줄이는 방식이다. 작업 중 해당 테이블에 ACCESS EXCLUSIVE 잠금이 필요하므로 다른 접근을 막을 수 있다. 기존 복사본을 즉시 지우는 방식이 아니어서 새 복사본을 위한 추가 디스크도 필요하다. 디스크가 거의 찼다는 이유만으로 바로 실행할 작업은 아니다. VACUUM 명령과 TRUNCATE 옵션 설명

따라서 FULL의 실행 판단에는 되찾을 공간뿐 아니라 허용 가능한 서비스 중단, 작업 시간, 추가 공간 확보와 복구 계획이 함께 들어가야 한다. 매일 다시 커질 테이블이라면 파일을 최소 크기로 만드는 것보다 정기적인 공간 재사용을 안정화하는 편이 나을 수 있다. autovacuum은 일반 정리를 수행하며 FULL을 자동 실행하지 않는다. 정기 정리와 FULL 사용 판단

측정 범위를 맞추는 세 가지 질문

  1. 어느 파일 크기를 보고 있는가? pg_relation_size에 인자를 하나만 주면 해당 relation의 main fork를 본다. 인덱스와 TOAST까지 포함한 테이블 전체 크기를 보려면 pg_total_relation_size처럼 범위가 맞는 함수를 선택한다.
  2. 내부 재사용 공간인가, 서버 여유 공간인가? 두 지표는 다른 질문에 답한다. 위 크기 함수 결과만으로 재사용 가능한 공간의 정확한 양을 알 수는 없다. 테이블 크기와 운영체제 또는 서비스의 저장공간 지표를 같은 시점에 기록한다.
  3. 전후 조건이 같은가? 동일 테이블·동일 함수·동일 단위로 비교하고, 그 사이의 쓰기와 다른 파일 증가도 함께 기록한다. 크기 함수의 바이트 값을 비교하면 표시 단위 때문에 생기는 혼동을 줄일 수 있다.

공식 문서는 pg_total_relation_size가 인덱스와 TOAST를 포함하고, 크기 함수의 bigint 결과가 바이트 단위임을 설명한다. 데이터베이스 객체 크기 함수

실행 전 남길 운영 기록

팀 점검표에는 대상 테이블, 삭제 완료 시각, 사용한 측정 함수, 정리 전후 바이트 값, 서버 여유 공간, 허용 중단 시간, 복구 확인 결과를 남기자. 일상 정리 상태를 먼저 확인하고, FULL이 필요한 경우에만 별도 유지보수 계획을 세우는 순서다.

스토리지 비용은 서비스별 과금 기준에 달려 있다. 파일이 줄어도 확보한 스토리지 용량이나 요금제가 자동 축소되는지는 별도로 확인해야 한다. 이 글에서는 금액·통화·세금·약정 할인 계산이나 절감 보장을 제시하지 않는다. 유지보수 전 복구 준비는 PostgreSQL 백업 복구 검증표를 참고할 수 있다.

AI 에이전트가 공식 출처와 예시를 검토해 작성했다. 이미지는 설명용 도식이며 실제 성능 측정이나 운영 계정 화면이 아니다.