PostgreSQL 19 Beta 2: SQL/PGQ 그래프 쿼리·REPACK·병렬 Autovacuum으로 달라지는 운영 경계
요약
PostgreSQL 19 Beta 2가 2026년 7월 16일 공개되면서 기능 동결(feature freeze)이 선언됐다. 이제 남은 일은 회귀 테스트, 버그 수정, 문서 완성이고, GA는 2026년 9월~10월로 예상된다.
Beta 2에서 확인된 핵심 변화는 세 가지다.
- SQL/PGQ: ISO SQL:2023 Part 16 표준 구현으로, 기존 관계형 테이블 위에서 그래프 패턴 매칭 쿼리가 가능해진다.
- REPACK [CONCURRENTLY]:
VACUUM FULL과pg_repack확장을 대체하는 내장 명령으로,CONCURRENTLY옵션 사용 시 테이블을 오프라인으로 만들지 않고 bloat을 제거한다. - 병렬 Autovacuum: 인덱스 vacuum을 여러 worker가 나눠 처리해 대형 테이블 vacuum 시간을 줄인다.
Beta 1(2026-06-04)에서 이미 포함됐던 ON CONFLICT DO SELECT, WAIT FOR LSN, 논리 복제 시퀀스 동기화, 재시작 없는 WAL 레벨 전환과 함께, DBA가 GA 전에 미리 파악해야 할 변화 전체를 살펴본다.
database-frontier/3에서 Beta 1을 다뤘다. 이 챕터는 Beta 2 이후 추가된 기능과 운영 관점 실무 가이드에 집중한다.
SQL/PGQ: 관계형 테이블을 그래프로 쿼리하기
배경: 그래프 데이터베이스가 따로 필요했던 이유
소셜 네트워크, 의존성 트리, 조직도, 지식 그래프처럼 "노드와 엣지"로 표현되는 데이터를 관계형 테이블로 다루는 건 오래된 고통이었다.
-- 기존: 재귀 CTE로 3단계 연결된 친구 찾기 (읽기 어렵고 느림)
WITH RECURSIVE friends AS (
SELECT user_id, friend_id, 1 AS depth FROM friendship WHERE user_id = 1
UNION ALL
SELECT f.user_id, fship.friend_id, fr.depth + 1
FROM friendship fship JOIN friends fr ON fship.user_id = fr.friend_id
WHERE fr.depth < 3
)
SELECT DISTINCT friend_id FROM friends WHERE depth = 3;SQL/PGQ는 이 문제를 표준화된 그래프 쿼리 문법으로 해결한다. 별도 그래프 DB 없이, 기존 테이블을 그대로 두고 그래프 뷰만 추가하면 된다.
CREATE PROPERTY GRAPH: 그래프 구조 정의
-- 기존 관계형 테이블
CREATE TABLE users (user_id int PRIMARY KEY, name text);
CREATE TABLE follows (src int REFERENCES users, dst int REFERENCES users);
-- 그래프 뷰 정의 (데이터 복사 없음, 카탈로그 항목만 생성)
CREATE PROPERTY GRAPH social_graph
VERTEX TABLES (
users LABEL Person PROPERTIES (user_id AS id, name)
)
EDGE TABLES (
follows
SOURCE KEY (src) REFERENCES users (user_id)
DESTINATION KEY (dst) REFERENCES users (user_id)
LABEL Follows
);CREATE PROPERTY GRAPH는 DDL이지만 데이터를 복사하거나 인덱스를 추가로 만들지 않는다. 카탈로그에 메타데이터를 쓰는 것뿐이므로 완료까지 밀리초 단위가 걸린다. DROP PROPERTY GRAPH도 마찬가지로 카탈로그 항목만 제거한다.
GRAPH_TABLE: 패턴 매칭 쿼리
-- 3단계 이내 연결된 사용자 찾기 (SQL/PGQ)
SELECT path_end_name
FROM social_graph, GRAPH_TABLE (social_graph
MATCH (start:Person {id: 1})-[:Follows]->{1,3}(target:Person)
COLUMNS (target.name AS path_end_name)
);핵심 구문은 MATCH (start)-[edge]->{min,max}(end) 패턴이다. 경로 양화사({1,3})로 최소·최대 홉 수를 지정할 수 있다.
주의사항 및 한계
- 경로 양화사 최대 홉: 매우 깊은 탐색(
{1,100})은 지수적으로 경로 수가 증가한다. WHERE 절로 결과를 일찍 필터링해야 한다. - 직접 인덱스 지정 불가: GRAPH_TABLE 내 패턴 매칭은 플래너가 내부적으로 관계형 조인으로 변환한다. 조인에 쓰이는 컬럼에 인덱스가 있어야 성능을 낼 수 있다.
- 그래프 vs RDBMS 전문 엔진: 수억 개 노드의 깊은 홉 탐색은 여전히 Neo4j, Amazon Neptune 같은 전문 그래프 DB가 유리하다. PostgreSQL의 SQL/PGQ는 기존 관계형 데이터에서 중간 규모 그래프 쿼리를 추가 인프라 없이 실행하는 용도에 적합하다.
REPACK [CONCURRENTLY]: 내장 pg_repack
문제: 테이블 bloat 제거의 어려움
PostgreSQL의 MVCC는 삭제·수정된 행을 즉시 지우지 않고 dead tuple로 남겨둔다. VACUUM이 dead tuple을 정리하지만, 테이블 파일 크기 자체를 줄이지는 않는다. 실제 공간을 회수하려면 테이블을 재구성해야 한다.
| 방법 | 잠금 | 소요 시간 | 공간 회수 | 클러스터 재정렬 |
|---|---|---|---|---|
VACUUM | 없음 (거의) | 빠름 | 없음 | 없음 |
VACUUM FULL | ACCESS EXCLUSIVE (전체) | 느림 | ✓ | 없음 |
CLUSTER ON idx | ACCESS EXCLUSIVE (전체) | 느림 | ✓ | ✓ |
pg_repack (확장) | 초기·완료 시 짧게 | 중간 | ✓ | ✓ |
REPACK (PG19) | 초기·완료 시 짧게 | 중간 | ✓ | 선택 |
REPACK CONCURRENTLY | 완료 시 극히 짧게 | 중간 | ✓ | 선택 |
REPACK 동작 방식
REPACK CONCURRENTLY는 pg_squeeze 확장의 설계를 PostgreSQL 코어에 통합한 것이다.
1. 새 빈 테이블 (shadow table) 생성
2. 원본 테이블에 이벤트 트리거 설치 → 변경사항을 별도 로그 테이블에 기록
3. 원본 테이블 내용을 shadow table로 복사 (잠금 없이 진행)
4. 복사 중 발생한 변경사항 (로그에서) shadow table에 적용
5. ACCESS EXCLUSIVE 잠금을 극히 짧게 잡고
→ shadow table을 원본 이름으로 교체
→ 원본 테이블 삭제
→ 이벤트 트리거 제거단계 5의 잠금은 통상 수 밀리초로, 온라인 서비스에서 연결이 잠깐 대기하는 수준이다. 355 MB bloated table 기준 실제 재구성 후 178 MB로 절반이 됐고, 재구성 중 INSERT가 들어왔어도 블로킹 없이 커밋됐다.
-- 기본 REPACK (완료 시 짧은 잠금)
REPACK TABLE orders;
-- CONCURRENTLY (잠금 최소화, 온라인 권장)
REPACK TABLE orders CONCURRENTLY;
-- 인덱스 기준으로 물리적 재정렬도 함께 (CLUSTER와 동일 효과)
REPACK TABLE orders CONCURRENTLY ON idx_orders_created_at;pg_repack 확장과의 관계
REPACK CONCURRENTLY는 pg_repack의 핵심 기능을 코어에 통합한 것이므로 기존 pg_repack 사용자는 PG 19 이후 확장 없이 동일 기능을 쓸 수 있다. 단, pg_repack은 별도 데몬 프로세스로 동작하는 추가 기능(정기 스케줄링 등)도 가지고 있어 일부 운영자는 여전히 병행 사용을 검토할 수 있다.
병렬 Autovacuum
기존 한계
PG 18까지 autovacuum worker 하나는 테이블 하나를 담당하되, 그 테이블의 인덱스를 순차적으로 vacuum한다. 대형 테이블에 인덱스가 10개 있으면 10개를 한 worker가 직렬로 처리한다.
테이블이 수백 GB이고 인덱스가 많으면 vacuum이 몇 시간씩 걸리고, 그동안 dead tuple이 계속 누적된다.
PG 19의 병렬 Autovacuum
# postgresql.conf
autovacuum_max_parallel_workers = 3 # 인덱스 vacuum에 추가 worker 최대 수하나의 autovacuum worker가 테이블 vacuum을 담당하고, 인덱스 vacuum 단계에서 추가 worker들이 각 인덱스를 나눠 처리한다. 인덱스 수 만큼 병렬화되지는 않고, autovacuum_max_parallel_workers까지만 동시에 투입된다.
주의: 이 파라미터는 전체 인스턴스 수준 설정이다. 단일 테이블이 이 worker를 독점하면 다른 테이블의 vacuum이 지연될 수 있다. 워크로드에 따라 보수적으로 1~2부터 시작하는 것을 권장한다.
개별 테이블에서 병렬 vacuum을 비활성화하려면:
ALTER TABLE large_table SET (autovacuum_max_parallel_workers = 0);Beta 1부터 포함된 핵심 변화
ON CONFLICT DO SELECT
-- PG 18: 삽입 충돌 시 "삽입 성공"만 반환 가능
INSERT INTO cache (key, val) VALUES ('k1', 'new')
ON CONFLICT (key) DO NOTHING;
-- PG 19: 충돌 시 기존 행을 SELECT로 반환 가능
INSERT INTO cache (key, val) VALUES ('k1', 'new')
ON CONFLICT (key) DO SELECT * FROM cache WHERE key = 'k1';캐시 레이어나 幂등 삽입 패턴에서 추가 SELECT 쿼리 없이 충돌 시 기존 값을 읽어올 수 있다. 왕복 횟수를 줄이는 효과가 있다.
WAIT FOR LSN: 읽기-후-쓰기 일관성
-- Replica에서 특정 LSN까지 도달을 기다린 후 쿼리
SELECT pg_wait_for_lsn('0/5A3B2F0');
SELECT * FROM orders WHERE order_id = 12345;기본 키 삽입 직후 replica에서 같은 행을 읽는 패턴에서, replica가 WAL을 적용했는지 확인하는 별도 로직 없이 WAIT FOR LSN이 해당 LSN 도달을 보장한다. 타임아웃을 설정해 무한 대기를 방지할 수 있다.
논리 복제 시퀀스 동기화
PG 18까지 논리 복제는 시퀀스를 복제하지 않아, 페일오버 시 시퀀스 값 충돌이 발생할 수 있었다. PG 19는 시퀀스 값을 자동으로 동기화한다.
-- Publication 정의 시 시퀀스 포함
CREATE PUBLICATION pub1 FOR ALL TABLES WITH (include_sequences);재시작 없는 WAL 레벨 전환
논리 복제를 시작하거나 끝낼 때 wal_level을 변경해야 하는데, PG 18까지는 서버 재시작이 필수였다. PG 19는 ALTER SYSTEM SET wal_level = logical; SELECT pg_reload_conf();만으로 온라인 전환이 가능하다.
GA 준비 체크리스트
| 항목 | 내용 | 권장 시점 |
|---|---|---|
| SQL/PGQ 시범 적용 | 재귀 CTE를 GRAPH_TABLE로 대체 가능한지 확인 | Beta 2 지금 |
| REPACK CONCURRENTLY 테스트 | 개발 환경에서 pg_repack 대비 동작 검증 | Beta 2 지금 |
| parallel autovacuum 실험 | autovacuum_max_parallel_workers 값 튜닝 | Beta 2 지금 |
| 확장 호환성 검사 | pg_repack, pg_partman, PostGIS 등 GA 릴리스 기다림 | RC 이후 |
| 업그레이드 경로 확인 | pg_upgrade 경로 테스트, logical replication 기반 무중단 업그레이드 검토 | RC 이후 |
ON CONFLICT DO SELECT 전환 | 기존 충돌 처리 로직 단순화 가능 여부 파악 | Beta 2 지금 |
업그레이드 방법
pg_upgrade: 동일 서버에서 구버전 → PG 19로 in-place 업그레이드. 주요 버전 업그레이드 표준 경로.- 논리 복제 기반: PG 17/18 primary에서 PG 19 standby로 논리 복제를 맺고, 트래픽 전환 후 old primary 종료. 무중단 업그레이드가 가능하지만 설정이 복잡하다.
- Blue-Green: 별도 PG 19 클러스터를 구성하고 데이터 마이그레이션 후 전환. 롤백이 가장 안전하지만 비용이 높다.
Open question: Beta 3에서 추가 변경이 있을 수 있다. RC 1이 나오기 전까지 운영 업그레이드는 권장하지 않는다.
요점 정리
PostgreSQL 19는 기능 폭이 넓은 릴리스다.
- SQL/PGQ는 관계형 데이터 위에서 그래프 쿼리를 허용한다. 별도 그래프 DB 없이 조직도, 소셜 관계, 의존성 분석을 SQL로 할 수 있다. 단, 전문 그래프 DB 수준의 깊은 홉 성능은 기대하기 어렵다.
- REPACK CONCURRENTLY는 pg_repack 확장을 코어에 통합해 bloat 제거의 표준 경로를 만들었다. 테이블을 오프라인으로 만들지 않아 대형 테이블 관리 운영 부담이 줄어든다.
- 병렬 Autovacuum은 인덱스가 많은 대형 테이블의 vacuum 시간을 단축한다.
autovacuum_max_parallel_workers를 보수적으로 조정하면서 효과를 측정해야 한다. - GA는 2026년 9월~10월로 예상된다. 지금 Beta 2에서 시범 적용하고, RC 이후 확장 호환성까지 확인하면 GA 직후 안정적인 업그레이드가 가능하다.
References
- PostgreSQL 19 Beta 2 공식 릴리스 노트: https://www.linuxcompatible.org/story/postgresql-19-beta-2-released-native-graph-queries-unified-repack-and-feature-freeze
- PostgreSQL 19 SQL/PGQ 공식 문서: https://www.postgresql.org/docs/19/ddl-property-graphs.html
- CREATE PROPERTY GRAPH 문서: https://www.postgresql.org/docs/19/sql-create-property-graph.html
- Neon — PostgreSQL 19 SQL/PGQ 가이드: https://neon.com/postgresql/postgresql-19/sql-pgq-graph-queries
- Neon — PostgreSQL 19 REPACK 명령 가이드: https://neon.com/postgresql/postgresql-19/repack-command
- CYBERTEC — Handling graphs with SQL/PGQ: https://www.cybertec-postgresql.com/en/handling-graphs-with-sql-pgq-in-postgresql/
- Scaling Postgres Ep.414 — REPACK CONCURRENTLY: https://www.scalingpostgres.com/episodes/414-repack-concurrently/
- JusDB — PostgreSQL 19 Beta New Features DBA Guide: https://www.jusdb.com/blog/postgresql-19-beta-new-features-dba-guide
- InfoQ — PostgreSQL 19 Graph Queries and Concurrent Repacking: https://www.infoq.com/news/2026/06/postgresql-19-graph-queries/
- PostgreSQL 19 Beta 1 릴리스 노트: https://www.postgresql.org/about/news/postgresql-19-beta-1-released-3313/