PostgreSQL 파티셔닝의 짧은 역사
PostgreSQL의 파티셔닝은 10 버전에서 선언적(declarative) 문법이 들어온 이후 꾸준히 성숙해왔다. 13에서 UPDATE로 파티션 간 row 이동이 가능해졌고, 14에서 DETACH PARTITION CONCURRENTLY가 추가됐다. 그리고 PG19에서 마침내 파티션 자체를 병합하고 분할하는 DDL이 들어온다.
ALTER TABLE ... SPLIT PARTITION ...
ALTER TABLE ... MERGE PARTITIONS ...
익숙한 문법이다. Oracle을 써본 사람이라면 20년 넘게 봐온 구문과 거의 판박이다. 다만 자세히 보면 문법과 제약에서 결정적인 차이들이 있다.
이전까지 PG에서는 어떻게 했나
PG18 이하에서 파티션을 병합하려면 이런 절차를 거쳤다.
- 새로운 합쳐진 파티션 테이블을 생성
- 기존 파티션에서
INSERT SELECT로 데이터 이동 - 기존 파티션
DETACH - 새 파티션
ATTACH - 기존 파티션
DROP
한 번에 트랜잭션으로 묶기도 까다롭고, 데이터 이동 중 ACCESS EXCLUSIVE LOCK이 걸려 서비스 가용성에도 영향을 준다. 분할도 마찬가지로 귀찮았다. Oracle에서는 한 줄이면 끝나는 작업이었다.
PostgreSQL 19의 새 문법
SPLIT과 MERGE 각각 예제로 보자.
SPLIT PARTITION
-- 원본 파티션 테이블
CREATE TABLE sales (
id bigint generated always as identity,
region text not null,
amount numeric
) PARTITION BY LIST (region);
CREATE TABLE sales_all PARTITION OF sales
FOR VALUES IN ('KR', 'JP', 'CN', 'US', 'UK');
-- 하나의 파티션을 셋으로 분할
ALTER TABLE sales SPLIT PARTITION sales_all INTO (
PARTITION sales_asia FOR VALUES IN ('KR', 'JP', 'CN'),
PARTITION sales_us FOR VALUES IN ('US'),
PARTITION sales_uk FOR VALUES IN ('UK')
);
MERGE PARTITIONS
-- 세 파티션을 하나로 합치기
ALTER TABLE sales MERGE PARTITIONS
(sales_asia, sales_us, sales_uk)
INTO sales_all;
핵심 포인트 몇 가지.
- 지원 타입: RANGE, LIST (HASH는 지원하지 않음)
- RANGE 파티션은 인접(adjacent) 해야 병합 가능
- LIST는 인접 제약 없음
- 소스 파티션들은 괄호
(...)로 감싼다 - 대상 파티션에
PARTITION키워드를 붙이지 않는다
Oracle의 문법
같은 일을 Oracle에서 하면 이렇게 된다. Oracle 쪽은 8i 시절부터 존재해온 문법이라 변주가 많다.
SPLIT PARTITION
-- RANGE 파티션 분할 (AT 값 기준)
ALTER TABLE sales SPLIT PARTITION sales_2026 AT (DATE '2026-07-01')
INTO (
PARTITION sales_2026_h1 TABLESPACE ts1,
PARTITION sales_2026_h2 TABLESPACE ts2
);
-- LIST 파티션 분할 (VALUES 기준)
ALTER TABLE sales SPLIT PARTITION sales_all
VALUES ('KR', 'JP', 'CN')
INTO (
PARTITION sales_asia,
PARTITION sales_rest
);
MERGE PARTITIONS
-- 기본 문법
ALTER TABLE sales MERGE PARTITIONS
sales_q1_2026, sales_q2_2026, sales_q3_2026, sales_q4_2026
INTO PARTITION sales_2026;
-- RANGE 전용 TO 단축 문법
ALTER TABLE sales MERGE PARTITIONS
sales_q1_2026 TO sales_q4_2026
INTO PARTITION sales_2026;
나란히 비교
문법 차이
| 항목 | PostgreSQL 19 | Oracle |
|---|---|---|
| MERGE 소스 지정 | MERGE PARTITIONS (p1, p2) 괄호 | MERGE PARTITIONS p1, p2 나열 |
| MERGE 대상 지정 | INTO p_new | INTO PARTITION p_new |
| SPLIT 경계 지정 | FOR VALUES IN (...) / FOR VALUES FROM ... TO ... | AT (value) (RANGE) / VALUES (...) (LIST) |
| RANGE 범위 병합 단축 | 없음 (일일이 나열) | p1 TO p4 단축 문법 |
| TABLESPACE 지정 | 각 대상 파티션마다 개별 | 동일 |
기능/제약 차이
| 항목 | PostgreSQL 19 | Oracle |
|---|---|---|
| 지원 파티션 타입 | RANGE, LIST | RANGE, LIST, SYSTEM |
| HASH 파티션 | 지원 안 함 | 지원 안 함 |
| RANGE 인접 조건 | 필요 | 필요 |
| LIST 인접 조건 | 불필요 | 불필요 |
| 락 수준 | ACCESS EXCLUSIVE (전 구간) | EXCLUSIVE + ONLINE 옵션 (EE 12.2+) |
| 실행 방식 | 단일 프로세스 | 병렬 실행 가능 |
실전에서 갈리는 지점 — 락과 온라인 실행
문법은 거의 맞춰졌다. 하지만 운영에서 진짜 갈리는 건 락과 온라인 실행 여부다.
PG19
공식 커밋 메시지와 depesz의 벤치(1천만 행 LIST 파티션 기준)에서 확인된 내용은 다음과 같다.
- 작업 전체 구간에서
ACCESS EXCLUSIVE LOCK유지 - 단일 프로세스에서 순차 실행
- 대규모 파티션에서는 실질적 다운타임이 발생할 수 있음
쓸모 있는 평가는 이렇다. “편의성은 크게 좋아졌지만, 온라인성은 Oracle을 따라잡지 못했다.” 한 줄 SQL로 간단히 표현할 수 있게 된 것만으로도 의미가 크지만, 수백 GB 파티션을 무중단으로 합칠 수 있는 수준은 아니다.
Oracle
Oracle Enterprise Edition 12.2부터 ONLINE 키워드로 DML 블로킹 없이 파티션을 합치거나 쪼갤 수 있다.
ALTER TABLE sales MERGE PARTITIONS
sales_q1_2026, sales_q2_2026
INTO PARTITION sales_h1_2026
ONLINE;
내부적으로는 shadow 구조를 만들고 점진적으로 데이터를 이관하는 방식이라, 배타 락 보유 시간이 거의 없다. Enterprise Edition 라이선스가 전제라는 게 큰 단서지만, 대형 운영 환경에서 체감되는 차이는 크다.
정리 — 어디까지 따라왔고, 어디까지 아직인가
따라잡은 것
- SPLIT/MERGE DDL 자체의 존재 — SQL 한 줄로 끝난다
- 지원 파티션 타입 (RANGE, LIST)
- 인접 조건 정책 (RANGE는 인접 필요, LIST는 무관)
- 다중 분할(한 파티션 → N개)과 다중 병합(N개 → 하나)
아직 못 따라온 것
- 온라인(ONLINE) 실행 — 대형 파티션은 실질적 다운타임이 남음
- 병렬 실행 — 단일 프로세스로만 처리
- RANGE 범위 병합 단축 문법(
p1 TO p4) 없음
PG의 역사적 약점 중 하나가 “큰 파티션 테이블의 유지보수가 DDL 한 줄로 안 끝난다"였다. PG19는 그 거리를 눈에 띄게 좁혔다. 다만 운영에서 가장 아픈 “락을 오래 붙잡는다"는 문제는 남아 있어서, 대형 테이블은 여전히 DETACH CONCURRENTLY + 수동 작업 전략을 병용해야 할 수 있다.
Oracle에서 PG로 넘어올 때 “내가 쓰던 그 문법, PG에도 있어요?“라는 질문의 목록이 하나씩 채워지고 있다. 이번은 파티션 병합/분할 차례였다.
참고