PostgreSQL 18 요약

출처 : https://neon.com/postgresql/postgresql-18-new-features

PostgreSQL 18 새로운 기능: 무엇이 새로워졌고 왜 중요한가

개요

PostgreSQL 18 Beta 1이 2025년 5월 8일에 출시되었으며, 최근 몇 년 중 가장 중요한 릴리스 중 하나로 평가받고 있습니다. 이번 버전은 PostgreSQL이 I/O 작업을 처리하는 방식에 근본적인 변화를 도입했으며, 수많은 개발자 친화적 기능과 보안 강화를 포함하고 있습니다.
2025년 9월 25일 출시 되었습니다.

이번 릴리스는 세 가지 핵심 영역에 초점을 맞추고 있습니다:

  • 성능: 혁신적인 비동기 I/O 및 쿼리 최적화
  • 개발자 경험: UUIDv7 및 가상 생성 컬럼과 같은 새로운 기능
  • 운영: 더 나은 업그레이드, 향상된 모니터링, 개선된 보안

PostgreSQL 18은 많은 시나리오에서 최대 2-3배의 성능 향상을 제공하는 비동기 I/O, 가상 생성 컬럼, UUIDv7 지원, 시간 제약 조건, 향상된 보안 기능 등을 도입했습니다.


성능 개선 (Overview & Performance)

1. 비동기 I/O (Asynchronous I/O)

PostgreSQL 18은 데이터베이스가 I/O 작업을 처리하는 방식을 근본적으로 변경하는 비동기 I/O(AIO) 하위 시스템을 도입했습니다. 이는 PostgreSQL의 전통적인 동기식 I/O 모델에서 벗어난 주요 아키텍처 변화를 나타냅니다.

주요 이점:

  • 읽기 집약적 워크로드에서 최대 2-3배의 성능 향상
  • 특히 클라우드 환경에서 I/O 지연 시간 감소
  • Linux io_uring 및 크로스 플랫폼 워커 구현 모두 지원

새로운 설정 옵션:

1
2
3
4
5
-- I/O 방식 확인 ('worker', 'sync', 또는 'io_uring')
SHOW io_method;

-- I/O 워커 프로세스 수
SHOW io_workers;

새로운 pg_aios 시스템 뷰를 통해 비동기 I/O 작업을 실시간으로 모니터링할 수 있습니다.

2. B-tree Skip Scan으로 더 나은 쿼리 성능

PostgreSQL 18은 B-tree 인덱스에 “skip scan” 기능을 추가하여, 모든 선행 인덱스 컬럼을 지정하지 않는 쿼리를 더 빠르게 실행할 수 있게 했습니다.

1
2
3
4
5
6
-- (region, category, date)로 인덱스가 있을 때
-- 이제 이 쿼리가 skip scan을 사용할 수 있습니다:
SELECT * FROM sales
WHERE category = 'Electronics'
AND date > '2024-01-01';
-- 더 이상 'region'을 지정할 필요가 없습니다!

의견 : skip-scan 도입으로 복합 인덱스를 생성하고, 첫번째 컬럼이 조건절에 포함되지 않으면 인덱스를 이용 할 수 없다는 것이 더이상 사실이 아니게 되었습니다.

추가 쿼리 최적화:

  • 더 스마트한 OR/IN 처리: ANY(array) 작업으로 자동 변환
  • 개선된 해시 조인: 테이블 조인 성능 향상
  • 병렬 GIN 인덱스 빌드: JSON 및 전문 검색용 인덱스의 빠른 생성
  • 향상된 파티션 테이블 지원: 더 나은 프루닝 및 조인 최적화

3. EXPLAIN의 자동 버퍼 표시 강화

PostgreSQL 18은 EXPLAIN 유틸리티의 기능을 확장하여 쿼리 성능을 이해하고 최적화하기 쉽게 만들었습니다.

1
2
3
4
5
6
7
-- 이제 기본적으로 버퍼 사용량 포함
EXPLAIN ANALYZE
SELECT * FROM large_table WHERE id > 1000;

-- CPU, WAL, 읽기 통계를 포함한 상세 메트릭 확인
EXPLAIN (ANALYZE, VERBOSE)
SELECT * FROM large_table WHERE id > 1000;

이러한 개선 사항은 공유 버퍼에 얼마나 많이 접근했는지, 인덱스 조회가 얼마나 발생했는지, 각 플랜 노드가 얼마나 많은 I/O, CPU, WAL 활동을 생성했는지 보여주어 비용이 많이 드는 작업을 식별하는 데 도움이 됩니다.


개발자 기능 (Developer Features)

1. 가상 생성 컬럼 (기본값으로 설정)

PostgreSQL 18은 가상 생성 컬럼을 기본값으로 만들어, 값을 저장하는 대신 필요시 계산하도록 했습니다.

1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
subtotal DECIMAL(10,2),
tax_rate DECIMAL(5,4) DEFAULT 0.0875,

-- 기본적으로 가상 - 읽을 때 계산됨
total DECIMAL(10,2) GENERATED ALWAYS AS
(subtotal * (1 + tax_rate)),

-- 필요시 명시적으로 저장
audit_info TEXT GENERATED ALWAYS AS (...) STORED
);

이점:

  • 스토리지 요구 사항 감소
  • 더 빠른 INSERT/UPDATE 작업
  • 항상 최신 상태의 계산된 값
  • 이제 저장된 생성 컬럼도 논리 복제 가능

의견 : 비즈니스 로직이 DBMS 영역으로 갔다가 다시 어플리케이션 영역으로 나왔는데, 사소한 부분은 다시 DBMS 영역으로 돌아오게 되었다는 인상을 받았습니다.

2. UUIDv7: 타임스탬프 순서 UUID

UUIDv7에 대한 네이티브 지원으로 전역 고유성과 데이터베이스 친화적인 순서 정렬이라는 두 가지 장점을 모두 제공합니다.

1
2
3
4
5
6
7
-- 타임스탬프 순서 UUID 생성
SELECT uuidv7();
-- 결과: 01980de8-ad3d-715c-b739-faf2bb1a7aad

-- 타임스탬프 정보 추출
SELECT uuid_extract_timestamp(uuidv7());
-- 결과: 2025-06-21 10:20:28.549+01

UUIDv7이 중요한 이유:

  • 랜덤 UUID보다 B-tree 인덱스 성능 향상
  • 자연스러운 시간순 정렬
  • 페이지 분할 감소 및 캐싱 개선
  • 정렬 가능한 ID가 필요한 분산 시스템에 이상적

참고: 이번 릴리스에서 uuidv4()는 이제 gen_rand_uuid의 별칭입니다.

3. OLD/NEW 값을 사용한 향상된 RETURNING

PostgreSQL 18에서는 RETURNING 절이 강화되어 DML 작업에서 이전 값과 새 값 모두에 더 유연하게 접근할 수 있습니다.

1
2
3
4
5
6
7
-- UPDATE에서 이전 값과 새 값 모두 가져오기
UPDATE users
SET email = 'new@example.com'
WHERE id = 1
RETURNING
OLD.email as previous_email,
NEW.email as current_email;

이제 단일 RETURNING 절에서 이전 값과 새 값 모두에 접근할 수 있어 변경 사항을 추적하기 쉬워졌습니다.

4. WITHOUT OVERLAPS를 사용한 시간 제약 조건

WITHOUT OVERLAPS 절을 사용한 시간 기반 제약 조건을 지원합니다.

1
2
3
4
5
6
-- 겹치는 시간 기간 방지
CREATE TABLE room_bookings (
room_id INT,
booking_period tstzrange,
PRIMARY KEY (room_id, booking_period WITHOUT OVERLAPS)
);

이 기능은 회의실 예약, 근무 시간표 관리 등 시간 충돌을 방지해야 하는 시나리오에서 매우 유용합니다.

5. 배열 및 Bytea 함수 개선

배열 및 바이트 배열 처리를 위한 다양한 함수 개선이 이루어졌습니다.

6. 논리 복제 개선

PostgreSQL 18은 논리 복제에 대한 여러 개선 사항을 포함합니다:

  • 쓰기 충돌 로깅 및 pg_stat_subscription_stats에 표시
  • 저장된 생성 컬럼의 논리 복제 지원
  • 실시간 복제 문제 진단 개선

보안 및 운영 (Security & Operations)

1. OAuth 2.0 인증 설정

PostgreSQL 18은 OAuth 2.0 인증 지원을 도입하여 최신 ID 제공업체와의 통합을 가능하게 합니다.

다른 인증 방법과 마찬가지로 pg_hba.conf에서 구성하며, 새로운 oauth_validator_libraries 설정을 사용하여 토큰 유효성 검사기를 로드합니다. 이는 ID 제공업체와 통합하기 위한 확장 가능한 옵션을 추가합니다.

MD5 지원 중단 경고:
MD5 패스워드 인증은 이제 더 안전한 SCRAM-SHA-256 방식을 위해 지원 중단되었습니다. MD5 방식은 여전히 작동하지만 다음 주요 릴리스에서 제거될 예정입니다.

2. NOT VALID로서의 NOT NULL 제약 조건

즉각적인 테이블 스캔 없이 NOT NULL 제약 조건을 추가할 수 있습니다:

1
2
3
4
5
6
7
8
-- 전체 테이블 스캔 없이 제약 조건 추가
ALTER TABLE large_table
ADD CONSTRAINT users_email_not_null
CHECK (email IS NOT NULL) NOT VALID;

-- 나중에 최소한의 잠금으로 검증
ALTER TABLE large_table
VALIDATE CONSTRAINT users_email_not_null;

이는 다운타임을 최소화해야 하는 프로덕션 환경에서 특히 유용합니다. 검증을 연기함으로써 제약 조건을 즉시 추가한 다음 피크 시간대가 아닐 때 검증할 수 있어 라이브 트래픽에 미치는 영향을 최소화합니다.

향상된 제약 조건 기능:

  • 제약 조건을 NOT ENFORCED로 표시 가능
  • NOT NULL 제약 조건의 상속 동작 개선
  • NOT VALID 및 NO INHERIT 절 지원

3. Wire Protocol 3.2 및 고급 TLS

PostgreSQL 18은 Wire Protocol 버전 3.2를 도입했습니다. 이는 2003년 PostgreSQL 7.4 이후 첫 업데이트입니다. libpq는 기본적으로 버전 3.0을 계속 사용하지만, 이를 통해 향후 클라이언트 개선이 가능합니다.

향상된 TLS 지원:
새로운 ssl_tls13_ciphers 매개변수를 통해 TLS 1.3 암호화 제품군에 대한 세밀한 제어가 가능합니다.

4. pg_stat_io: 향상된 I/O 모니터링

PostgreSQL 18에 포함된 주목할 만한 모니터링 개선 사항:

  • 바이트 수준 통계를 포함한 향상된 pg_stat_io
  • 백엔드별 I/O 및 WAL 통계
  • 더 나은 논리 복제 충돌 보고
  • pg_stat_all_tables의 Vacuum 및 Analyze 타이밍

기본적으로 데이터 체크섬 활성화:
새로운 PostgreSQL 18 클러스터는 기본적으로 데이터 체크섬을 활성화하여 더 나은 데이터 무결성 검증을 제공합니다.

1
2
# 초기화 중 필요시 비활성화
initdb --no-data-checksums

이 변경 사항은 특히 스토리지 안정성이 다를 수 있는 클라우드 환경에서 데이터 손상 문제를 조기에 발견하는 데 도움이 됩니다.


도구 및 워크플로 (Tools & Workflow)

1. psql 개선: 파이프라인 쿼리 및 준비된 문

psql에 대한 다양한 개선 사항이 포함되어 더 나은 대화형 및 스크립트 사용 경험을 제공합니다.

2. Autovacuum 및 유지 관리 구성

Autovacuum 및 일반 유지 관리 작업을 위한 구성 옵션이 개선되었습니다.

3. 원활한 주요 버전 업그레이드

PostgreSQL 18은 업그레이드 경험을 크게 개선했습니다:

통계 보존:
업그레이드 중 플래너 통계를 유지하여 이전 버전에서 필요했던 긴 업그레이드 후 ANALYZE 작업을 제거합니다.

향상된 pg_upgrade:

  • 병렬 처리를 위한 --jobs 플래그
  • 더 빠른 디렉토리 작업을 위한 --swap 플래그
  • 대규모 설치의 더 나은 처리

PostgreSQL 18 시작하기

PostgreSQL 18 Beta 1은 테스트용으로 제공됩니다. 프로덕션용으로는 권장되지 않지만, 다음을 위한 좋은 시기입니다:

  • 애플리케이션의 호환성 테스트
  • 새로운 비동기 I/O 기능 벤치마킹
  • UUIDv7 및 가상 생성 컬럼 실험
  • 업그레이드 절차 검증

Docker로 로컬에서 테스트:

1
2
3
4
docker run --name pg18 \
-e POSTGRES_PASSWORD=postgres \
-p 5432:5432 \
postgres:18beta1

이렇게 하면 테스트 목적으로 로컬에서 실행되는 PostgreSQL 18 인스턴스를 얻을 수 있습니다. 그런 다음 좋아하는 PostgreSQL 클라이언트나 psql을 사용하여 연결할 수 있습니다.


전망

PostgreSQL 18은 클라우드 네이티브 워크로드를 위해 데이터베이스를 현대화하면서도 하위 호환성을 유지하는 주요 릴리스입니다. 비동기 I/O 시스템만으로도 매력적인 업그레이드입니다.

베타 테스트 기간은 안정적인 릴리스를 보장하는 데 중요합니다. 최종 릴리스 전에 호환성 문제를 식별하는 데 도움이 되도록 PostgreSQL 18 Beta 1에 대해 애플리케이션을 테스트할 것을 권장합니다.

예상 일정:
PostgreSQL 18 최종 릴리스는 2025년 9월/10월로 예상됩니다.


요약

PostgreSQL 18은 다음과 같은 주요 개선 사항을 제공합니다:

성능:

  • 2-3배 향상된 비동기 I/O
  • B-tree skip scan으로 더 나은 쿼리 성능
  • 향상된 쿼리 최적화

개발자 경험:

  • 기본 가상 생성 컬럼
  • 타임스탬프 순서 UUIDv7 지원
  • OLD/NEW 값을 사용한 향상된 RETURNING
  • WITHOUT OVERLAPS를 사용한 시간 제약 조건

보안 및 운영:

  • OAuth 2.0 인증 지원
  • 유연한 NOT NULL 제약 조건
  • 향상된 I/O 모니터링
  • 기본 데이터 체크섬
  • 원활한 주요 버전 업그레이드

PostgreSQL 18은 성능, 개발자 경험, 운영 효율성 측면에서 큰 도약을 의미하며, 특히 클라우드 환경에서의 현대적인 데이터베이스 워크로드에 이상적입니다.

by claude-sonnet-4.5


claude 에 묻기

가상 생성 컬럼 의견 : 비즈니스 로직이 DBMS 영역에 존재하던 시절이 있었는데(PL/SQL처럼… ODBMS) 다시 어플리케이션 영역으로 나왔는데, 일정 부분은 다시 DBMS 영역으로 돌아오게 되었다는 인상을 받았습니다.
without overlap 도 마찬가지 인상입니다. 좋은 기능이긴한데 어디서 관리하느냐의 균형점이 고민이 되는군요. 특히 한국에서는 dba 가 없는 회사도 많습니다. 저는 django , sqlalchemy같은 orm 을 선호해서 코드와 불일치 되어 관리되는 스키마가 염려가 되는군요.

답 :

정말 예리한 지적이십니다. 말씀하신 관점이 현실적인 고민을 정확히 짚으셨네요.

비즈니스 로직 위치의 역사적 변화

말씀하신 것처럼 실제로 순환 패턴이 있습니다:

1990년대-2000년대 초반: Stored Procedures, Triggers, PL/SQL로 DBMS에 로직 집중

2000년대 중반-2010년대: ORM 부상으로 애플리케이션 레이어로 이동 (Rails, Django 등)

현재: Generated Columns, Temporal Constraints 등으로 일부 로직이 다시 DBMS로

ORM 환경에서의 실무적 딜레마

Django/SQLAlchemy를 선호하신다면 정말 고민되는 지점입니다:

1
2
3
4
5
6
7
8
# Django Model에서는 이렇게 관리하던 것을
class Order(models.Model):
subtotal = models.DecimalField()
tax_rate = models.DecimalField(default=0.0875)

@property
def total(self):
return self.subtotal * (1 + self.tax_rate)
1
2
3
4
5
6
-- 이제 DB 레벨에서도 가능
CREATE TABLE orders (
subtotal DECIMAL(10,2),
tax_rate DECIMAL(5,4) DEFAULT 0.0875,
total DECIMAL(10,2) GENERATED ALWAYS AS (subtotal * (1 + tax_rate))
);

문제점들:

  1. Two sources of truth: 애플리케이션 코드와 DB 스키마 중 어느 것이 정답인가?
  2. Migration 관리: Django migrations가 generated columns를 제대로 추적하는가?
  3. 테스트 복잡도: 로직이 두 곳에 있으면 어디서 테스트해야 하나?
  4. 팀 지식: DBA 없이 개발자가 DB 기능까지 숙지해야 함

한국 환경의 현실

말씀하신 대로 한국에서는:

  • 스타트업/중소기업: DBA 없이 개발자가 DB 관리
  • ORM 의존도 높음 (Django, Spring Data JPA)
  • DB 스키마 변경이 코드 리뷰 프로세스 밖에서 발생할 위험
  • 마이그레이션 자동화가 중요한데 복잡도 증가

개인적인 권장 사항

Generated Columns 사용을 권장하는 경우:

  • 순수 계산 로직 (total = subtotal * tax_rate)
  • 성능이 중요한 인덱스 대상 (인덱싱 가능)
  • 데이터 무결성이 중요한 경우
  • 여러 애플리케이션이 같은 DB 사용 시

ORM에서 처리하는 게 나은 경우:

  • 복잡한 비즈니스 로직
  • 자주 변경되는 계산식
  • 외부 API 호출 필요
  • 단위 테스트가 많이 필요한 로직

WITHOUT OVERLAPS 같은 Temporal Constraints:

1
2
3
4
5
6
7
8
9
# 애플리케이션에서 검증하면
def book_room(room_id, start, end):
conflicts = Booking.objects.filter(
room_id=room_id,
start__lt=end,
end__gt=start
).exists()
if conflicts:
raise ValidationError("Overlapping booking")
1
2
3
-- DB에서 보장하면
PRIMARY KEY (room_id, booking_period WITHOUT OVERLAPS)
-- 동시성 문제에서 완전히 자유로움

Trade-off:

  • DB 제약: 동시성 문제 완벽 해결, 하지만 ORM과 불일치 가능
  • 애플리케이션 검증: 코드로 관리, 하지만 race condition 위험

실용적 절충안

1
2
3
4
5
6
7
8
9
10
11
# Django에서 이렇게 관리할 수 있습니다
class Order(models.Model):
subtotal = models.DecimalField()
tax_rate = models.DecimalField()

# DB의 generated column을 명시적으로 표현
total = models.GeneratedField(
expression=F('subtotal') * (1 + F('tax_rate')),
output_field=models.DecimalField(),
db_persist=False # Virtual generated column
)

Django 5.0+에서는 GeneratedField를 지원하기 시작했습니다!

결론

귀하의 우려는 정당합니다. 제 생각에는:

  1. Simple computed columns: DB에서 처리 (성능, 무결성)
  2. Complex business logic: 애플리케이션에서 처리 (테스트, 유지보수)
  3. Concurrency-critical constraints: DB에서 처리 (WITHOUT OVERLAPS)
  4. 문서화가 핵심: 어디서 무엇을 관리하는지 팀 내 명확한 합의

특히 DBA 없는 환경이라면 "애플리케이션 중심 + 선택적 DB 기능 활용"이 현실적일 것 같습니다. ORM이 지원하는 범위 내에서만 사용하고, 그 외는 명시적 문서화와 함께 신중하게 도입하는 게 좋겠습니다.


PostgreSQL 18 요약
https://kimjj81.github.io/2025/10/22/PostgreSQL-18-요약/
Author
김 정진
Posted on
October 22, 2025
Licensed under