Trawling

Craig Kerstiens, PostgreSQL 19 온라인 REPACK 시험 결과 공개

PostgreSQL 19의 내장 `REPACK (CONCURRENTLY)`는 테이블을 새 파일로 재작성하면서 작업 중 변경을 WAL 논리 디코딩으로 반영해, 대량 작업 중에도 읽기와 쓰기를 허용합니다. Snowflake Engineering Blog의 Craig Kerstiens가 공개한 CPU 1개·메모리 512MB 환경 시험에서 100만 행이 남은 493MB 테이블을 재작성하는 데 온라인 방식은 9.4초, `VACUUM FULL`은 2.7초가 걸렸습니다. 온라인 방식은 더 오래 걸렸지만 마지막 파일 교체 단계에서만 강한 잠금을 잡았으며, 사용에는 추가 저장 공간과 스냅샷 관련 제약이 따릅니다.

본문

PostgreSQL 19에 추가되는 내장 SQL 명령 REPACK (CONCURRENTLY)는 테이블을 새 파일로 다시 써 디스크 공간을 회수하면서, 작업 대부분의 시간에 읽기와 쓰기를 허용합니다. Snowflake Engineering Blog에 글을 쓴 Craig Kerstiens는 493MB 테이블 비교에서 온라인 방식이 VACUUM FULL보다 오래 걸렸지만 작업 중 테이블 접근을 유지했다고 보고했습니다.

PostgreSQL은 행을 갱신하거나 삭제할 때 이전 행 버전을 남기는 MVCC 방식으로 동시 접근을 처리합니다. 일반 VACUUM은 쓸모없어진 행이 차지하던 공간을 테이블 안에서 재사용하도록 표시하지만, 파일 크기를 줄여 디스크 공간을 운영체제에 돌려주지는 않습니다. 쓰기 작업이 많은 큰 테이블에서는 오래된 행이 쌓여 파일이 커질 수 있고, 실제 공간을 회수하려면 테이블을 다시 써야 합니다.

기존 VACUUM FULL도 테이블을 다시 써서 공간을 회수하지만, 작업 내내 읽기와 쓰기를 막는 잠금을 잡습니다. 확장 프로그램 pg_repack은 데이터베이스 확장과 별도 실행 파일을 설치해 온라인 재작성을 처리하며, 작업 중 발생한 변경을 트리거와 로그 테이블로 기록합니다. PostgreSQL 19의 REPACK (CONCURRENTLY)는 이 기능을 서버 내장 명령으로 제공하고, 변경 기록에는 WAL 기반 논리 디코딩을 사용합니다.

동시 방식은 원본 테이블에서 쓸모없는 행을 제외한 새 사본과 인덱스 파일을 만들면서, 그 사이 발생한 변경을 WAL 논리 디코딩으로 포착해 새 사본에 반영합니다. 대량 작업 중에는 다른 세션도 테이블을 읽고 쓸 수 있습니다. 마무리 단계에서 ACCESS EXCLUSIVE 잠금을 얻은 뒤 남은 변경을 반영하고 파일을 교체합니다. 이 잠금은 보통 짧게 유지되지만, 잠금을 기다리는 동안 쌓인 변경량에 따라 길이가 달라집니다. 변경을 포착하고 다시 적용하는 과정이 더해져 잠금 방식보다 처리 시간이 늘어날 수 있습니다.

Kerstiens는 CPU 1개, 메모리 512MB, maintenance_work_mem 4MB 환경에서 비교했습니다. 시험 대상은 처음 200만 행이 있던 493MB 테이블에서 100만 행을 삭제해 100만 행이 남은 상태였습니다. 이 작업에 VACUUM FULL은 2.7초, 잠금 방식 REPACK은 5.9초, REPACK (CONCURRENTLY)는 9.4초가 걸렸습니다. 세 방식 모두 완료 뒤 테이블 크기는 228MB였습니다. 앞의 두 방식은 작업 내내 테이블 접근을 막았고, 동시 방식은 마지막 파일 교체 단계에서 강한 잠금을 잡았습니다. 이는 한 가지 제한된 시험의 결과이며, 글은 시간 차이가 테이블과 인덱스, 작업량, 하드웨어에 따라 달라진다고 설명합니다.

정기적인 행 정리와 공간 재사용은 자동 VACUUM이 맡고, 파일 크기를 줄여 디스크 공간을 돌려받으려면 테이블을 다시 써야 합니다. 작업 시간 동안 접근 중단을 허용할 수 있으면 VACUUM FULL이나 잠금 방식 REPACK을 선택할 수 있고, 읽기와 쓰기를 계속 허용해야 하면 추가 처리 시간을 들여 동시 방식을 사용할 수 있습니다.

온라인 재작성은 기존 테이블과 인덱스를 둔 채 새 사본을 만들므로 작업 중 추가 저장 공간이 필요합니다. PostgreSQL 공식 문서는 REPACK (CONCURRENTLY)가 UNLOGGED 테이블과 파티션 테이블 등을 지원하지 않는다고 명시합니다. 또 동시 방식은 완전한 MVCC 안전성을 제공하지 않습니다. 재작성 시작 전 스냅샷을 사용하는 트랜잭션은 작업이 끝난 뒤 테이블을 빈 상태로 볼 수 있습니다.

PostgreSQL 프로젝트는 2026년 10월 15일 RC1을 공개했고, Kerstiens의 글은 11월 2일 게시됐습니다. 11월 4일 현재 프로젝트는 RC2를 11월 12일, 정식판을 11월 19일로 계획했습니다. 추가 문제가 발견되면 정식판 일정이 바뀔 수 있습니다.

자료: Snowflake Engineering Blog, PostgreSQL / 정리·해설: Trawling

참고 자료

오류 제보