LLM WikiAccess-protected knowledge portal

WIKI

PostgreSQL 19 Beta 2: SQL/PGQ 그래프 쿼리·REPACK CONCURRENTLY·병렬 오토베이큠으로 달라진 운영 기준

2026년 여름, PostgreSQL이 바뀌는 방향 2026년 7월 16일, PostgreSQL 개발팀은 PostgreSQL 19 Beta 2 를 공개하며 기능 동결 feature freeze 을 선언했다. 이제 GA 2026년 9월~10월 예정 까지는 안정성 개선에만 집중한다는 뜻이다. 이번 릴리스에서 DBA와 플랫폼 엔지니어가 주목할 변화는 크게 세 가지다. 첫째, 별도 그래프 DB 없이 기존 관계형 테이블에 그래프 패턴

경로human/study/content/database-frontier/83-postgresql-19-beta2-sqlpgq-repack-parallel-autovacuum.md
카테고리Study
태그#autovacuum #beta2 #mysql #parallel #repack #sqlpgq #study

2026년 여름, PostgreSQL이 바뀌는 방향

2026년 7월 16일, PostgreSQL 개발팀은 PostgreSQL 19 Beta 2를 공개하며 기능 동결(feature freeze)을 선언했다. 이제 GA(2026년 9월~10월 예정)까지는 안정성 개선에만 집중한다는 뜻이다.

이번 릴리스에서 DBA와 플랫폼 엔지니어가 주목할 변화는 크게 세 가지다. 첫째, 별도 그래프 DB 없이 기존 관계형 테이블에 그래프 패턴 매칭 쿼리를 실행할 수 있는 SQL/PGQ. 둘째, pg_repack과 pg_squeeze를 코어로 흡수한 REPACK CONCURRENTLY. 셋째, 오토베이큠이 대형 테이블을 병렬로 처리하는 병렬 오토베이큠. 이 외에도 플래너 제어를 위한 pg_plan_advice, 시퀀스 논리 복제, 기본값 변경 등 운영 관점에서 점검해야 할 사항들이 있다.


SQL/PGQ: 그래프 쿼리를 관계형 테이블 위에서

배경

소셜 네트워크 분석, 추천 엔진, 권한 경로 탐색 같은 그래프 패턴 쿼리를 PostgreSQL로 처리하려면 지금까지는 복잡한 CTE나 재귀 쿼리를 작성해야 했다. 관계를 그래프로 표현하기 위해 Neo4j 같은 전용 그래프 DB를 추가 운영하는 팀도 있었다.

PostgreSQL 19는 SQL:2023 표준의 SQL/PGQ(Property Graph Queries) 를 코어에 구현한다. 기존 관계형 테이블을 프로퍼티 그래프로 선언하고, 표준 SQL 문법으로 노드와 엣지를 순회하는 쿼리를 실행할 수 있다. 별도 그래프 엔진 없이 PostgreSQL 하나로 처리된다.

작동 방식

-- 1단계: 프로퍼티 그래프 정의
CREATE PROPERTY GRAPH social_graph
  VERTEX TABLES (
    users LABEL Person PROPERTIES (id, name, age)
  )
  EDGE TABLES (
    follows SOURCE KEY (follower_id) REFERENCES users (id)
             DESTINATION KEY (followee_id) REFERENCES users (id)
             LABEL Follows
  );

-- 2단계: GRAPH_TABLE로 패턴 매칭 쿼리
SELECT p1.name AS follower, p2.name AS following
FROM GRAPH_TABLE(social_graph
  MATCH (p1 IS Person)-[IS Follows]->(p2 IS Person)
  WHERE p1.age > 25
  COLUMNS (p1.name, p2.name)
);

CREATE PROPERTY GRAPH는 뷰처럼 동작한다. 실제 데이터는 기존 테이블(users, follows)에 그대로 있고, 그래프 정의는 이 테이블들을 노드/엣지로 해석하는 메타데이터다. GRAPH_TABLE 함수는 이 정의를 참조해 MATCH 패턴을 일반 관계형 쿼리로 번역한 뒤 실행한다.

현재 제한

Beta 2 기준으로 고정 깊이 패턴 매칭만 지원한다. ->*, ->+, ->{2,5} 같은 가변 길이 경로 순회는 지원하지 않는다. 최단 경로나 도달 가능성 같은 전형적인 그래프 알고리즘은 PostgreSQL 19 범위 밖이며, 향후 버전에서 다룰 예정이다.

기존 테이블 구조를 바꾸지 않고 그래프 정의를 얹는 방식이므로, 이미 관계형 스키마로 설계된 데이터에 그래프 질의를 추가하는 용도로 가장 적합하다.


REPACK CONCURRENTLY: 온라인 테이블 재구성의 표준화

REPACK CONCURRENTLY 내부 단계 ① 초기 복사 SHARE UPDATE EXCLUSIVE MVCC 스냅샷 기준 원본 테이블: 읽기/쓰기 허용 (VACUUM과 동일 잠금 수준) ② 변경 포착 내부 복제 슬롯 자동 생성 논리 디코딩으로 변경 사항 섀도 테이블에 지속 적용 (복사 진행 중 발생한 DML 추적) ③ 인덱스 재구성 섀도 테이블 기준으로 새 인덱스 파일 생성 원본 서비스 중단 없음 (정렬 순서 변경 가능) ④ 파일 스왑 (독점 잠금) ACCESS EXCLUSIVE 획득 섀도 ↔ 원본 파일 교체 복제 슬롯 삭제 (테이블 크기와 무관한 짧은 시간) 기존 방법 vs REPACK CONCURRENTLY 비교 VACUUM FULL / CLUSTER 처음부터 끝까지 ACCESS EXCLUSIVE → 전체 작업 중 테이블 잠김 대형 테이블: 수십 분 ~ 수시간 프로덕션 유지보수 윈도우 필요 읽기·쓰기 모두 불가 코어 내장, 별도 확장 불필요 하지만 서비스 중단 위험 pg_repack / pg_squeeze 논리 복제 기반 온라인 재구성 최종 스왑만 짧은 잠금 외부 확장(extension) 필요 버전별 호환성 확인 필수 대부분의 시간 읽기·쓰기 허용 확장 설치·관리 오버헤드 → PostgreSQL 19에서 코어 통합 REPACK CONCURRENTLY (PG 19) 코어 내장 + 온라인 동작 확장 없이도 동일 효과 내부 복제 슬롯 자동 관리 최종 스왑만 ACCESS EXCLUSIVE 전 구간 읽기·쓰기 허용 VACUUM FULL, CLUSTER, pg_repack, pg_squeeze를 단일 명령으로 통합 운영 주의사항: CONCURRENTLY 없이 REPACK만 쓰면 ACCESS EXCLUSIVE가 전 구간 유지됩니다 VACUUM FULL과 동일 동작 → 프로덕션에서는 반드시 REPACK CONCURRENTLY 사용
PostgreSQL 19 REPACK CONCURRENTLY — 내부 동작 흐름

핵심 메커니즘

REPACK CONCURRENTLY는 내부적으로 다음 순서로 동작한다.

  1. SHARE UPDATE EXCLUSIVE 잠금 하에 원본 테이블의 MVCC 스냅샷을 기준으로 섀도 테이블에 데이터를 복사한다. VACUUM, ANALYZE와 같은 잠금 수준이므로 서비스 트래픽은 계속 처리된다.
  2. 내부적으로 논리 복제 슬롯을 생성해 복사 진행 중 발생한 INSERT/UPDATE/DELETE를 포착하고 섀도 테이블에 반영한다.
  3. 섀도 테이블 기준으로 새 인덱스 파일을 생성한다.
  4. 섀도 테이블과 원본의 변경 격차가 줄어들면 ACCESS EXCLUSIVE를 짧게 획득해 파일 포인터를 교체한다. 교체 자체는 테이블 크기와 무관하게 빠르게 완료된다.

REPACK(CONCURRENTLY 없이)은 처음부터 끝까지 ACCESS EXCLUSIVE를 유지하므로, 프로덕션에서는 항상 CONCURRENTLY 옵션을 써야 한다.

pg_repack 사용자 마이그레이션 경로

PostgreSQL 19로 업그레이드하면 REPACK CONCURRENTLY가 코어 명령으로 제공된다. 기존에 pg_repack이나 pg_squeeze 확장을 사용하던 팀은 REPACK CONCURRENTLY로 전환할 수 있다. 내부 메커니즘이 pg_squeeze 로직을 코어로 가져온 것이라 동작 방식은 본질적으로 동일하다.


병렬 오토베이큠

문제

대형 테이블에서 오토베이큠이 한 번 실행되면 단일 워커가 처음부터 끝까지 처리한다. 수억 행 규모의 테이블에서는 오토베이큠 한 라운드가 수십 분 걸리고, 그 사이 dead tuple이 계속 쌓인다.

PostgreSQL 19의 해결

-- 오토베이큠 병렬 워커 수 설정
ALTER SYSTEM SET autovacuum_max_parallel_workers = 4;
SELECT pg_reload_conf();

-- 테이블별 세밀한 제어도 가능
ALTER TABLE orders SET (autovacuum_max_parallel_workers = 2);

autovacuum_max_parallel_workers GUC로 오토베이큠이 사용할 최대 병렬 워커 수를 설정한다. 각 테이블 처리 시 지정된 수의 워커가 협력해 블록을 나누어 처리한다.

처리 우선순위 조정: 새 GUC autovacuum_freeze_score_weightautovacuum_vacuum_score_weight로 freeze 긴급도와 일반 vacuum 긴급도에 각각 가중치를 부여할 수 있다. 기존에는 단순한 임계값 기반이었던 테이블 우선순위 결정이 점수 기반 시스템으로 바뀐다.

운영 시 주의

병렬 워커가 늘어난 만큼 I/O 압력도 커진다. autovacuum_vacuum_cost_delayautovacuum_vacuum_cost_limit 설정을 함께 조정해 쓰기 부하가 높은 프로덕션 환경에서 autovacuum이 서비스 성능을 잠식하지 않도록 해야 한다.


pg_plan_advice: 플래너 힌트의 공식화

배경

PostgreSQL 플래너가 잘못된 실행계획을 선택하는 경우, 기존에는 공식적인 힌트 메커니즘이 없었다. pg_hint_plan 같은 외부 확장을 사용하거나, enable_seqscan = off 같은 전역 GUC를 임시로 변경하는 우회법을 써야 했다.

pg_plan_advice 확장

PostgreSQL 19는 pg_plan_advice 확장을 번들로 제공한다.

-- 확장 활성화
CREATE EXTENSION pg_plan_advice;

-- 쿼리 실행계획 분석 및 어드바이스 생성
SELECT * FROM pg_get_advice('SELECT * FROM orders WHERE customer_id = 12345');

-- 어드바이스를 쿼리 식별자 기반으로 자동 적용
SELECT * FROM pg_stash_advice(query_id := 'abc123', advice := '...');

플래너가 비효율적인 계획을 택할 때 어드바이스를 생성·저장하고, 이후 동일 쿼리 식별자로 실행되는 요청에 자동으로 적용한다. 전역 GUC 변경 없이 특정 쿼리에만 힌트를 줄 수 있다.

Oracle의 SQL Plan Management(SPM), MySQL의 optimizer_hints와 유사한 방향이지만, PostgreSQL 방식으로 확장 형태로 제공한다.


시퀀스 논리 복제

PostgreSQL 18까지 논리 복제(logical replication)는 테이블 행만 복제했다. 시퀀스의 현재 값은 복제 대상이 아니었기 때문에, 페일오버 후 스탠바이를 프라이머리로 승격하면 시퀀스 값이 페일오버 시점 이전에 머물러 있었다.

PostgreSQL 19에서는 시퀀스 값도 논리 복제로 동기화된다. Publication에 시퀀스를 포함시키고 Subscription 쪽에서 동기화하는 방식이다.

-- Publisher: 시퀀스 포함
CREATE PUBLICATION my_pub FOR ALL TABLES, SEQUENCES;

-- Subscriber: 시퀀스 즉시 동기화
ALTER SUBSCRIPTION my_sub REFRESH PUBLICATION WITH (copy_data = true);

이로써 페일오버 후 중복 키(duplicate key) 오류가 발생하는 흔한 문제를 논리 복제 설정 하나로 방지할 수 있다.


기타 주목할 변화

GROUP BY ALL

-- 기존: 집계 아닌 컬럼을 수동으로 열거해야 함
SELECT region, category, SUM(sales)
FROM orders
GROUP BY region, category;

-- PostgreSQL 19: ALL이 집계 아닌 컬럼을 자동 포함
SELECT region, category, SUM(sales)
FROM orders
GROUP BY ALL;

GROUP BY ALL은 SELECT 목록에서 집계 함수에 포함되지 않은 컬럼을 자동으로 GROUP BY에 추가한다. 분석 쿼리 작성 시 오류를 줄이고 타이핑을 줄여주는 문법 편의 기능이다.

새 모니터링 뷰

기본값 변경

설정PostgreSQL 18 기본값PostgreSQL 19 기본값
TOAST 압축pglzlz4
JIT(Just-in-Time)onoff

TOAST 압축 기본값 lz4 전환: lz4는 pglz보다 압축률은 약간 낮지만 압축/해제 속도가 훨씬 빠르다. 대용량 텍스트나 JSONB 컬럼이 많은 데이터베이스에서 I/O가 줄어들면서 전체 성능이 올라가는 경우가 많다. 단, pg_dump로 백업한 데이터를 PostgreSQL 17 이하로 복구할 때 lz4로 압축된 TOAST 값을 처리하지 못할 수 있으므로 버전 간 마이그레이션 계획에서 확인이 필요하다.

JIT 기본 비활성화: JIT는 복잡한 집계 쿼리에서 이득이 있지만 소규모 쿼리에서 컴파일 오버헤드로 지연이 생기는 경우가 있었다. 기본값 off로 바꿔 대다수 OLTP 워크로드에서 일관성을 확보하고, JIT가 효과적인 OLAP 워크로드에서만 명시적으로 활성화하도록 유도한다.


DBA 체크리스트 (GA 대비)

Open question: pg_plan_advice가 프로덕션에서 얼마나 안정적으로 동작하는지는 GA 이후 커뮤니티 피드백을 통해 확인이 필요하다. Beta 2 단계에서 확장을 바로 프로덕션에 적용하기보다 테스트 환경에서 동작을 검증하는 것을 권장한다.


References