본문 바로가기
Database2026년 4월 30일8분 읽기

PostgreSQL 18 핵심 기능 — uuidv7·비동기 I/O·Skip Scan·OAuth 한 번에 정리

YS
김영삼
조회 465
PostgreSQL 18 핵심 기능 — uuidv7·비동기 I/O·Skip Scan·OAuth 한 번에 정리

핵심 요약

PostgreSQL 18은 2003년 7.4 이후 첫 wire protocol 변경(3.2)을 포함한 대규모 릴리스다. 비동기 I/O로 일부 워크로드 최대 3배, uuidv7·OAuth·temporal constraints 같은 실무에 직접 영향 주는 기능이 한 번에 들어왔다.

  • 비동기 I/O 서브시스템 (sequential scan·bitmap heap scan·VACUUM)
  • Skip scan — 멀티컬럼 B-tree 인덱스 활용 범위 확대
  • uuidv7() 내장 함수 — 시간 정렬 UUID
  • Virtual generated columns (default)
  • RETURNING에 OLD/NEW
  • OAuth 인증
  • 업그레이드 시 통계 보존

1. 비동기 I/O — 왜 3배 빠른가

이전 PG는 한 페이지를 읽고 처리한 후 다음 페이지를 요청하는 동기 I/O였다. 18은 이미 다음 페이지들을 prefetch하면서 처리한다.

-- 18에서 활성화 확인
SHOW io_method;  -- worker | io_uring | sync

-- 워크로드별 권장:
-- io_uring (Linux 5.1+) — 가장 빠름
-- worker — 안정성 우선
-- sync — 호환 모드
워크로드17 vs 18 (worker)
full table scan1.8~2.5x
VACUUM2.0~3.0x
bitmap heap scan1.5~2.0x
OLTP 단건 조회변화 없음

2. uuidv7() — 드디어 인덱스 친화적 UUID

uuidv4의 가장 큰 문제는 랜덤이라 B-tree 인덱스 페이지가 끊임없이 split되는 것. uuidv7은 timestamp prefix가 있어 정렬 가능.

-- 17까지: 외부 라이브러리 또는 수동 구현
CREATE TABLE orders (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),  -- v4
  ...
);

-- 18: 네이티브
CREATE TABLE orders (
  id uuid PRIMARY KEY DEFAULT uuidv7(),  -- 시간 정렬
  ...
);

실측 효과

  • INSERT 쓰루풋 +30~50% (페이지 split 감소)
  • 같은 시간대 row가 같은 페이지 → 캐시 히트율↑
  • id로 ORDER BY ASC하면 시간순으로 정렬됨

3. Skip Scan — 멀티컬럼 인덱스 활용 확대

이전엔 idx (a, b)에서 WHERE b = 1은 인덱스를 못 썼다. 18은 a의 distinct 값이 적으면 자동 skip scan.

CREATE INDEX ON orders (status, created_at);

-- 17: status 조건이 없으면 seq scan
-- 18: status가 ('pending','paid','shipped') 같이 카디널리티 낮으면
SELECT * FROM orders WHERE created_at >= '2026-04-01';
-- → skip scan 자동 사용

4. Virtual Generated Columns (default)

-- 17: STORED만 가능 (디스크에 저장)
CREATE TABLE products (
  price_cents int,
  tax_cents int GENERATED ALWAYS AS (price_cents * 0.1) STORED
);

-- 18: VIRTUAL이 default (계산만)
CREATE TABLE products (
  price_cents int,
  tax_cents int GENERATED ALWAYS AS (price_cents * 0.1) -- VIRTUAL
);
-- 디스크 절약, INSERT/UPDATE 빠름
-- 단, 인덱스는 STORED만 가능

5. RETURNING의 OLD/NEW

UPDATE/DELETE 시 변경 전후 값을 한 번에 받기. 트리거나 별도 SELECT 없이 audit log 가능.

UPDATE accounts
SET balance = balance - 100
WHERE id = 42
RETURNING old.balance AS before, new.balance AS after;
-- 결과: before=500, after=400

-- MERGE에서도
MERGE INTO inventory ...
RETURNING merge_action(), old.qty, new.qty;

6. OAuth 인증

-- pg_hba.conf
host all all 0.0.0.0/0 oauth issuer="https://accounts.google.com"   scope="openid email" map=oauth_users

-- pg_ident.conf
oauth_users  /^(.+)@example\.com$  \1

각 클라우드 IdP를 직접 통합. 비밀번호 회전·관리에서 해방.

7. Temporal Constraints

예약 시스템에서 같은 자원이 시간 겹치게 들어가는 걸 DB 레벨에서 차단:

CREATE TABLE bookings (
  id serial PRIMARY KEY,
  room_id int,
  during tsrange,
  EXCLUDE USING gist (room_id WITH =, during WITH &&)  -- 17까지 가능
);

-- 18: PRIMARY KEY/UNIQUE/FOREIGN KEY에도 temporal
CREATE TABLE rates (
  product_id int,
  during tsrange,
  rate numeric,
  PRIMARY KEY (product_id, during WITHOUT OVERLAPS)
);

8. 업그레이드 시 통계 보존

17 이전엔 pg_upgrade 후 ANALYZE 안 하면 쿼리 플래너가 엉망이라 한동안 성능 저하. 18은 통계 함께 마이그레이션.

pg_upgrade --copy-statistics ...
# 업그레이드 직후 정상 성능

9. 마이그레이션 체크리스트

  1. Extension 호환성 확인 (PostGIS·pgvector 등 18 대응판 확인)
  2. uuidv4 → uuidv7 마이그레이션 검토 (새 테이블만, 기존은 그대로)
  3. STORED generated column → VIRTUAL 후보 발굴
  4. io_method 설정 (Linux는 io_uring)
  5. OAuth 도입 검토 (특히 multi-tenant SaaS)

10. 함정·주의점

  • 비동기 I/O는 IOPS 압박 큰 환경에선 더 빨라지지만, 디스크 대역폭 한계 환경에선 별 차이 없을 수 있다
  • Virtual generated column에 인덱스 못 만든다 — 인덱스 필요하면 STORED
  • uuidv7도 보안 식별자로 쓸 땐 주의 — timestamp가 노출됨. URL 식별자엔 ULID/snowflake 권장
  • protocol 3.2는 옵션. 3.0 클라이언트도 계속 동작

자주 묻는 질문

RDS·Aurora는 언제?

AWS는 통상 6~12개월 후. 18은 2025년 9월 GA → 2026년 상반기 RDS, 후반기 Aurora 예상.

uuidv7 vs ULID vs snowflake?

uuidv7은 표준 + DB 네이티브로 가장 깔끔. ULID는 외부 라이브러리 필요하지만 base32라 짧음. snowflake는 워커 ID 관리 필요.

17에서 18로 다운타임?

pg_upgrade는 수 분~십수 분. logical replication 사용하면 거의 0. 통계 보존 덕에 업그레이드 후 워밍업 불필요.

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록