프로덕션용 PostgreSQL 17: 파티셔닝 개선·COPY 진행·실제 중요한 기능들
출처: Dev.to
프로덕션 환경에서 PostgreSQL 17: 실제로 중요한 점
PostgreSQL 17은 점진적인 개선과 몇 가지 진정한 혁신을 혼합해서 출시되었습니다. 몇 달간 프로덕션에서 운영해 본 결과, 일상 업무에 실제로 변화를 가져온 부분은 다음과 같습니다.
파티션 프루닝이 크게 개선되었습니다
파티션 테이블을 사용하고 있다면(특히 대용량 시계열 데이터를 다루는 경우라면 반드시 사용해야 함) 이는 큰 업그레이드가 됩니다.
-- PG17 이전에는 이 쿼리가 파티션을 효율적으로 프루닝하지 못할 수 있음
EXPLAIN SELECT * FROM events
WHERE event_date BETWEEN '2026-01-01' AND '2026-03-31'
AND event_type = 'purchase';
-- 결과: events에 대한 Seq Scan (많은 파티션이 스캔됨)
-- event_date에 파티션이 있더라도 event_type 필터가
-- 효과적인 프루닝을 방해함
-- PG17은 파티션 키가 아니더라도 여러 컬럼을 기준으로 프루닝 가능
EXPLAIN SELECT * FROM events
WHERE event_date BETWEEN '2026-01-01' AND '2026-03-31'
AND event_type = 'purchase';
-- 이제: 관련 파티션만 스캔
-- 추가 필터가 있더라도 PG17은 더 효과적으로 프루닝함
-- PG17 이전에는 파티션 단위 조인이 해시 조인에서만 동작했음
-- PG17은 이를 머지 조인까지 확장함
-- 예시: 지역별로 파티션된 sales와 products
-- PG17은 파티션 레벨에서 머지 조인을 수행할 수 있음
EXPLAIN SELECT s.sale_id, p.product_name, s.amount
FROM sales s
JOIN products p ON s.region = p.region AND s.product_id = p.id
WHERE s.sale_date >= '2026-01-01';
-- PG17은 이제 조인을 개별 파티션으로 내려보내
-- 모든 데이터를 모은 뒤 조인하는 것이 아니라 파티션 수준에서 조인함
COPY 명령이 크게 개선되었습니다
- PG17은 특정 파일 포맷에 대해
COPY FROM을 병렬화할 수 있습니다. 이는 데이터 로딩 시 큰 병목이었는데, 이제 크게 해소됩니다.
-- 병렬 임포트를 위한 테이블 생성
CREATE TABLE large_events (
id BIGSERIAL,
event_type TEXT,
event_data JSONB,
created_at TIMESTAMPTZ
) PARTITION BY RANGE (created_at);
-- PG17: 대용량 파일에 대해 이제 병렬 워커를 사용할 수 있음
COPY large_events (event_type, event_data, created_at)
FROM '/data/events_2026.csv'
WITH (FORMAT csv, HEADER true);
-- 성능 개선: 멀티코어 시스템에서 2~4배 빠름
-- 대용량 CSV 임포트 시
-- 바이너리 포맷에 대한 COPY는 이제 더 신뢰성이 높아지고
-- 엣지 케이스를 더 잘 처리함
COPY events TO '/tmp/events.bin' (FORMAT binary);
COPY events FROM '/tmp/events.bin' (FORMAT binary);
-- PG17은 바이너리에서 NULL 처리와 혼합된 NULL/데이터 행에 대한 성능을 개선함
JSON_TABLE 도입
JSON에 대해 관계형 스타일로 질의할 수 있는 JSON_TABLE이 추가되었습니다. 반정형 데이터 작업이 크게 편해집니다.
-- 샘플 데이터
CREATE TABLE api_logs (
id BIGSERIAL PRIMARY KEY,
request JSONB
);
-- JSON을 테이블처럼 조회
SELECT jt.method, jt.path, jt.status
FROM api_logs,
JSON_TABLE(
request,
'$.request'
COLUMNS (
method TEXT PATH '$.method',
path TEXT PATH '$.path',
status INT PATH '$.status'
)
) AS jt
WHERE jt.status >= 400;
-- 이는 MongoDB의 집계 파이프라인에 대응하는 PostgreSQL의 기능임
증분 정렬이 더 똑똑해졌습니다 (PG13에 도입, PG17에서 개선)
더 많은 쿼리 패턴에서 증분 정렬을 활용할 수 있습니다.
EXPLAIN SELECT customer_id, order_date, total
FROM orders
WHERE order_date >= '2026-01-01'
ORDER BY customer_id, order_date DESC;
-- PG17 이전: 증분 정렬을 사용하지 않을 수 있음
-- PG17: customer_id로 초기 정렬 후 order_date DESC에 대해 증분 정렬 사용 가능
새로운 집계 함수들
-- 중복 제거된 LISTAGG
SELECT
customer_id,
LISTAGG(DISTINCT product_category, ', ') WITHIN GROUP (ORDER BY product_category)
FROM orders
GROUP BY customer_id;
-- 최빈값을 구하는 mode()
SELECT
department,
MODE() WITHIN GROUP (ORDER BY salary) AS common_salary
FROM employees
GROUP BY department;
-- 최신 값을 반환하는 any_value() (정렬 기반)
SELECT
product_id,
ANY_VALUE(purchases ORDER BY purchase_date DESC) AS latest_purchase
FROM purchases
GROUP BY product_id;
외부 도구 없이 WAL 내용 검사
복제 디버깅에 매우 유용합니다.
SELECT * FROM pg_walinspect('000000010000000000000001', '000000010000000000000002');
-- 반환값: WAL 레코드 상세, LSN 범위, 트랜잭션 정보
-- 이전에는 pg_receivewal 또는 서드파티 도구 필요
연결 풀링 문제는 아직 해결되지 않음
1,000개 이상의 연결을 다루려면 여전히 PgBouncer 또는 pgpool-II가 필요합니다.
# pg_bouncer.ini
[databases]
mydb = host=127.0.0.1 port=5432 dbname=mydb
[pgbouncer]
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 25
파티션 관리 자동화는 아직 미흡
파티션 성능은 개선됐지만, 새로운 파티션을 자동으로 생성해 주지는 않습니다.
-- 새 파티션을 수동으로 생성해야 함
CREATE TABLE events_2026_q2 PARTITION OF events
FOR VALUES FROM ('2026-04-01') TO ('2026-07-01');
-- 시간 시계열 데이터에 대해 자동 파티션 생성 기능이 없으므로
-- 운영 부담이 여전히 큼
업그레이드 경로는 간단합니다
1. PG16과 함께 PG17 설치
brew install postgresql@17
2. pg_upgrade 실행 (인플레이스)
pg_upgrade \
-d /usr/local/var/postgresql@16 \
-D /usr/local/var/postgresql@17 \
-b /usr/local/Cellar/postgresql@16/16.0/bin \
-B /usr/local/Cellar/postgresql@17/17.0/bin
3. 새 클러스터 분석 (pg_upgrade가 자동으로 수행)
./analyze_new_cluster.sh
- 500 GB 데이터베이스 전체 다운타임: 약 4분
- 대부분의 프로덕션 시스템에서 충분히 허용 가능
PG17에서 stricter(엄격)해진 동작
-
regproc형 변환은 이제 명시적인 함수 호출이 필요합니다.
이전:SELECT 'now'::regproc;
이제:SELECT 'now'::regprocedure; -
일부 JSON 경로 표현식이 동작 방식이 달라졌습니다.
업그레이드 후 JSON 쿼리를 반드시 테스트하세요. -
pg_hba.conf변경: 일부 레거시 인증 옵션이 폐기되었습니다.
성능 비교 표
| Query Type | PG16 | PG17 | Improvement |
|---|---|---|---|
| Range partition prune | 45ms | 8ms | 82% faster |
| Partition-wise join | 230ms | 95ms | 59% faster |
| COPY FROM 10M rows | 45s | 18 |