PostgreSQL 18 徹底解説:uuidv7、仮想カラム、新I/Oエンジン
Engineering Team
簡潔な回答
PostgreSQL 18は、PostgreSQL 12がプラグ可能なテーブルアクセスメソッドを導入して以来、最も重要なリリースです。主要機能——書き直された非同期I/Oサブシステム、ネイティブuuidv7()生成、仮想生成カラム、時制制約——は、以前は拡張機能、回避策、または全く異なるデータベースを必要としていた長年のギャップに対処しています。PostgreSQL 17を本番環境で実行している場合、今すぐアップグレードの計画を開始すべきです。移行パスは簡単で、新しいI/Oエンジンだけでもパフォーマンス向上がその努力を正当化します。
リリースの背景
PostgreSQL 18は2025年9月18日にリリースされ、プロジェクトの年次リリースサイクルに従っています。I/Oサブシステムの書き直しにはバッファマネージャー、WALライター、VACUUMサブシステムへの同時変更が必要だったため、開発サイクルは通常より長くなりました。380人以上のコントリビューターがこのリリースにコードを提出し、PostgreSQL史上最多のコントリビューター数となりました。
このリリースは、PostgreSQLが新規プロジェクトのデフォルトデータベースとなった時期に登場しました。2025年のStack Overflow Developer SurveyではPostgreSQLが3年連続で最も使用されているデータベースとして49.1%を獲得し、MySQL(40.2%)とSQLite(32.6%)を上回りました。
新しい非同期I/Oサブシステム
PostgreSQL 18で最もインパクトのある変更は、書き直されたI/Oサブシステムです。以前のPostgreSQLバージョンはディスクからデータページを読み取るために同期シングルスレッドI/Oを使用していました。新しいサブシステムはLinuxでio_uring、macOS/BSDでkqueueを使用した真の非同期I/Oを導入し、他のプラットフォームではワーカースレッドベースの非同期I/Oにフォールバックします。
仕組み
従来のPostgreSQL I/Oパスはシンプルでした:クエリがshared_buffersにないページを必要とする場合、バックエンドプロセスは同期read()コールを発行し、カーネルがデータを返すまでブロックしました。これは100GBテーブルのシーケンシャルスキャンがNVMeドライブの数に関係なくシングルスレッドI/Oにボトルネックされることを意味しました。
新しいサブシステムはI/Oリクエストをバッチ処理します。エグゼキュータがページ1、5、12、47が必要だと判断すると(例えばbitmap heap scanから)、io_uringを通じて4つの読み取りリクエストすべてを同時にカーネルに送信します。
パフォーマンスへの影響
標準NVMe SSD構成(4x NVMe RAID-0)でのベンチマーク:
| ワークロード | PG 17 | PG 18 | 改善 |
|---|---|---|---|
| シーケンシャルスキャン(コールドキャッシュ) | 1.2 GB/s | 3.4 GB/s | 2.8倍 |
| Bitmap heap scan | 890 MB/s | 2.6 GB/s | 2.9倍 |
| VACUUM(大テーブル) | 45分 | 18分 | 2.5倍 |
| パラレルインデックス構築 | 12分 | 5.5分 | 2.2倍 |
| WAL書き込みスループット | 1.8 GB/s | 3.1 GB/s | 1.7倍 |
モダンNVMeストレージ上のI/Oバウンドワークロードで改善が最も顕著です。データベースが完全にshared_buffersに収まる場合、変化はわずかです。ワーキングセットがRAMを超える場合——分析ワークロード、時系列データ、大規模JSONBストアでよくあること——改善は変革的です。
設定
新しいI/Oサブシステムはデフォルトで有効です。2つの新しいGUCパラメータがその動作を制御します:
-- バックエンドあたりの最大同時I/Oリクエスト数(デフォルト:128)
SET io_max_concurrency = 128;
-- I/Oメソッド:'io_uring'、'kqueue'、'worker'(自動検出)
SET io_method = 'io_uring';
ほとんどのインストールではデフォルトが最適です。ハイエンドNVMeアレイ(8+ドライブ)と非常に大きなシーケンシャルスキャンのワークロードがある場合はio_max_concurrencyを増やしてください。
uuidv7():ネイティブのタイムスタンプ順UUID
PostgreSQL 18はuuidv7()関数を追加し、RFC 9562準拠のバージョン7 UUIDを生成します。これはコミュニティが何年も要望していた機能で、以前はpgcryptoまたはuuid-ossp拡張とカスタム関数の組み合わせが必要でした。
なぜuuidv7が重要か
UUIDv4(ランダム)はプライマリキーとして最も一般的に使用されるUUIDバージョンです。データベースパフォーマンスに致命的な欠陥があります:ランダムUUIDはB-treeインデックスでランダムI/Oパターンを引き起こします。UUIDv4プライマリキーで新しい行を挿入すると、対象のインデックスリーフページは基本的にランダムで、キャッシュミスと書き込み増幅を引き起こします。
UUIDv7は最初の48ビットにUnixタイムスタンプをエンコードし、その後にユニーク性のためのランダムビットが続きます。つまりUUIDv7の値はBIGSERIALのように時間とともに単調増加しますが、調整なしにグローバルにユニークです。
-- UUIDv7を生成
SELECT uuidv7();
-- 結果:019271a4-5b00-7123-8456-789abcdef012
-- UUIDv7からタイムスタンプを抽出
SELECT uuid_extract_timestamp('019271a4-5b00-7123-8456-789abcdef012');
-- 結果:2025-09-18 14:30:00+00
-- デフォルトプライマリキーとして使用
CREATE TABLE events (
id UUID PRIMARY KEY DEFAULT uuidv7(),
event_type TEXT NOT NULL,
payload JSONB,
created_at TIMESTAMPTZ DEFAULT now()
);
パフォーマンス比較
1億行のテーブルで:
| メトリック | UUIDv4 PK | UUIDv7 PK | BIGSERIAL PK |
|---|---|---|---|
| 挿入レート(行/秒) | 45,000 | 112,000 | 125,000 |
| インデックスサイズ | 4.2 GB | 4.2 GB | 2.1 GB |
| インデックスキャッシュヒット率 | 67% | 94% | 96% |
| ポイントルックアップレイテンシ(p99) | 2.1 ms | 0.4 ms | 0.3 ms |
UUIDv7はグローバルユニーク性を維持しながら、BIGSERIALに近い挿入パフォーマンスを達成します。分散システム、マイクロサービス、データベース調整なしにアプリケーション層でIDを生成する必要のあるアーキテクチャでは、uuidv7が明確なデフォルト選択になりました。
仮想生成カラム
PostgreSQLはバージョン12以降、格納生成カラムをサポートしています。PostgreSQL 18は仮想生成カラムを追加しました——読み取り時に計算され、ディスクに格納されません。
CREATE TABLE products (
id UUID PRIMARY KEY DEFAULT uuidv7(),
name TEXT NOT NULL,
price_cents INTEGER NOT NULL,
tax_rate NUMERIC(5,4) NOT NULL DEFAULT 0.11,
-- 仮想:読み取り時に計算、ストレージコストゼロ
price_with_tax NUMERIC GENERATED ALWAYS AS (price_cents * (1 + tax_rate)) VIRTUAL,
-- 格納:書き込み時に計算、ディスク領域を占有
search_vector TSVECTOR GENERATED ALWAYS AS (to_tsvector('english', name)) STORED
);
VIRTUALとSTOREDの使い分け
VIRTUALを使う場合:
- 計算が安価(算術、文字列結合、型キャスト)
- ストレージオーバーヘッドゼロが望ましい
- カラムがまれにクエリされるか行とともにのみクエリされる
- 値が常に現在のデータを反映してほしい
STOREDを使う場合:
- 計算が高価(全文検索ベクトル、複雑なJSON抽出)
- 生成カラムにインデックスが必要
- カラムがWHEREやJOINで頻繁に使用される
仮想カラムはディスクにインデックス対象のデータがないため直接インデックスできません。計算値でのフィルタリングやソートが頻繁な場合はSTOREDを使用してください。
OAuth認証サポート
PostgreSQL 18はpg_hba.confにOAuth 2.0 / OpenID Connectをネイティブ認証メソッドとして追加しました。Okta、Auth0、Azure AD、Keycloakなどのアイデンティティプロバイダーに対して認証できます。
# pg_hba.conf
host all all 0.0.0.0/0 oauth issuer="https://auth.company.com" client_id="pg-prod"
時制制約
PostgreSQL 18は期間カラムを持つテーブルに時制PRIMARY KEY、UNIQUE、FOREIGN KEY制約を導入しました。これはSQL:2011の時制機能をPostgreSQLにもたらします。
CREATE TABLE employee_departments (
employee_id INTEGER NOT NULL,
department_id INTEGER NOT NULL,
valid_from DATE NOT NULL,
valid_to DATE NOT NULL,
PERIOD FOR valid_period (valid_from, valid_to),
PRIMARY KEY (employee_id, valid_period WITHOUT OVERLAPS)
);
時制制約は同じエンティティの重複期間を防止します——時間範囲データを管理するアプリケーション(サブスクリプション、料金体系、ロール割り当て、在庫予約)における一般的なバグの原因です。
RETURNING句でのOLD/NEW
PostgreSQL 18はUPDATEおよびDELETE文のRETURNING句でOLDおよびNEWテーブル値を参照できます。
UPDATE products
SET price_cents = price_cents * 1.1
WHERE category = 'electronics'
RETURNING
id,
OLD.price_cents AS previous_price,
NEW.price_cents AS updated_price,
name;
マルチカラムB-treeインデックスのSkip-Scan
PostgreSQL 18はマルチカラムB-treeインデックスのskip-scan最適化を導入しました。クエリのWHERE句に先頭カラムがない場合でもプランナーが複合インデックスを効率的に使用できます。
CREATE INDEX idx_locations ON locations (country, city, population);
-- PG 17:フルインデックススキャン
-- PG 18:Skip-scan(異なる'country'値間をジャンプ)
SELECT * FROM locations WHERE city = 'Jakarta';
移行ガイド:PostgreSQL 17から18へ
アップグレード前チェックリスト
- 拡張機能の互換性を確認。 PG 18テストインスタンスで
SELECT * FROM pg_available_extensions;を実行。 - pg_hba.confを確認。 新しいOAuthメソッドは追加的——既存の認証設定はそのまま動作します。
- I/Oパフォーマンスをテスト。 新しい非同期I/Oサブシステムはデフォルトで有効です。
- 生成カラムを監査。 格納生成カラムを仮想に変換する場合、インデックスが依存していないことを確認。
- アプリケーションクエリをテスト。 skip-scanオプティマイザの変更によりクエリプランが変わる可能性があります。
アップグレード方法
pg_upgrade(ほとんどの場合推奨):
pg_ctl -D /var/lib/postgresql/17/data stop
pg_upgrade \
--old-datadir=/var/lib/postgresql/17/data \
--new-datadir=/var/lib/postgresql/18/data \
--old-bindir=/usr/lib/postgresql/17/bin \
--new-bindir=/usr/lib/postgresql/18/bin \
--link
pg_ctl -D /var/lib/postgresql/18/data start
vacuumdb --all --analyze-in-stages
論理レプリケーション(ゼロダウンタイム): PG 17からPG 18への論理レプリケーションを設定し、同期完了後にアプリケーションの接続文字列を切り替えます。
マネージドサービス: AWS RDS、Google Cloud SQL、Azure Database、Neonはすべて最小限のダウンタイムでメジャーバージョンアップグレードをサポートしています。
FAQ
PostgreSQL 18は本番環境対応ですか?
はい。PostgreSQLは厳格なリリースプロセスに従っています。.0リリースは本番品質です。ただし、リスク回避型の組織にとって.1パッチリリース(通常.0の2-3ヶ月後)を待つのは合理的な戦略です。
既存テーブルのUUIDv4からUUIDv7に切り替えるべきですか?
新しいテーブルにはuuidv7()をデフォルトとして使用してください。既存のUUIDv4プライマリキーのテーブルでは、測定可能なインデックス膨張やキャッシュミスの問題がない限り、移行コストはメリットを正当化しません。
新しいI/Oエンジンにカーネルの変更は必要ですか?
io_uringサポートにはLinuxカーネル5.10以降が必要です。カーネルが古い場合、PostgreSQL 18はワーカースレッドベースの非同期I/Oにフォールバックします。
pgvectorで仮想カラムを使用できますか?
直接はできません。pgvectorのエンベディングは通常、計算ではなく格納されます。ただし、vector_dims(embedding)やl2_distance(embedding, reference_vector)のような派生メトリックには仮想カラムを使用できます。
時制制約はパーティショニングとどう連携しますか?
時制制約は宣言的パーティショニングで機能します。期間カラムの範囲でテーブルをパーティション分割し、時制PRIMARY KEY制約を適用できます。
MERGEの改善はどうなりましたか?
PostgreSQL 18はMERGE文にRETURNING句のサポートを追加し、PG 15で導入された機能セットを完成させました。