リリーススケジュールとこの記事の基準
PostgreSQL 19は2026年9月24日にベータ4がリリースされました。公式アナウンスによると次の段階は10月初めのリリース候補(RC)で、テスト結果次第では正式版(GA)も10月にリリースされる可能性があります。ベータ段階のため、細かな動作はまだ変わる可能性があります。この記事はベータ4時点の公式リリースノートを基準にしています。
まず知っておくべき点があります。ベータ4で、次の機能は19から外されました。安定性と予測可能なスケジュールを優先し、以降のメジャーバージョンに見送られたものです。
- SQL/PGQ(プロパティグラフクエリ)
- データチェックサムのオンラインでの有効化・無効化
FOR PORTION OFを使う時間範囲のUPDATE/DELETEALTER TABLE ... MERGE PARTITIONS/SPLIT PARTITIONS
開発中に紹介された解説記事の中には、これらの機能や GROUP BY ALL のように、ベータ4のリリースノートにない機能を19の機能として扱ったものがあります。アップグレード計画はリリースノートで確認してください。
1. REPACK:VACUUM FULLとCLUSTERを統合し、ロックなしで実行
テーブルが更新・削除で肥大化すると、領域を取り戻すために VACUUM FULL や CLUSTER を使っていましたが、どちらも実行中ずっとテーブルをロックするため、サービス稼働中には使いにくいものでした。19では両コマンドに代わる REPACK が追加され、CONCURRENTLY オプションを指定すると、読み書きをブロックせずにテーブルを書き直します。
-- 領域の回収(実行中も読み書き可能)
REPACK (CONCURRENTLY, VERBOSE) orders;
-- インデックス順の物理的な並べ替え(クラスタリング)まで
REPACK (CONCURRENTLY) orders USING INDEX orders_ordered_at_idx;
仕組みは次のとおりです。新しいテーブルを作成している間に入ってきた変更を論理デコーディングで集めて反映し、最も強いロック(ACCESS EXCLUSIVE)はファイルを差し替える短い瞬間にだけ取得します。
設計の観点で重要なのは、CONCURRENTLY を使えない条件です。
- 主キーも、インデックスベースのレプリカ識別子(replica identity)もないテーブル
- パーティションテーブル、
UNLOGGEDテーブル - トランザクションブロック内で実行する場合
max_repack_replication_slotsがこれ以上レプリケーションスロットを許可しない場合
つまり、すべてのテーブルに主キーを持たせることが、これからは運用ツールを使えるかどうかの問題になります。また、公式ドキュメントは CONCURRENTLY がMVCCセーフではないと警告しているため、実行中に長時間動いているトランザクションから見えるデータに関する注意事項(ドキュメントの13.6節)を読んでから使ってください。
2. CHECK制約もENFORCED / NOT ENFORCEDを切り替え可能に
PostgreSQL 18から、CHECK制約と外部キー制約を NOT ENFORCED として宣言できるようになりました。19では、ALTER CONSTRAINT でCHECK制約を適用するかどうかを後から変更できます(18までは外部キーのみ可能)。ENFORCED に変更すると、既存の行がルールを守っているかを確認したうえで、新しい行にも適用します。
-- 既存データに違反がありうるルールを、まずは宣言だけしておく
ALTER TABLE orders
ADD CONSTRAINT orders_amount_positive CHECK (amount_krw > 0) NOT ENFORCED;
-- 違反データを整理してから適用
ALTER TABLE orders ALTER CONSTRAINT orders_amount_positive ENFORCED;
ルールを先にスキーマ上でドキュメント化しておき、データの整理が終わってから実際に強制する、段階的なマイグレーションに使えます。
3. 外部キーのチェックが速くなる
リリースノートの概要では、パフォーマンス改善の項目としてより高速な外部キーチェックが挙げられています。外部キーの多い正規化されたスキーマで、書き込みコストが下がる方向の変化です(改善幅はワークロードごとに異なるため、実際に測定してみてください)。このほか、CREATE SCHEMA の中で、まだ作成していないテーブルを外部キーで前方参照できるようになりました。
4. アップグレード前に確認すべき動作の変更
互換性の項目のうち、アプリケーションに影響しうるものです。
standard_conforming_stringsが常にオン:通常の文字列リテラル内のバックスラッシュをエスケープとして解釈する動作に依存しているコードがあれば、確認が必要です- 結果行のない
json_array()呼び出しが、NULLではなく空のJSON配列を返す:IS NULLで「なし」を判定していたクエリは結果が変わります max_locks_per_transactionのデフォルト値が64 → 128- データベース・ロール・テーブルスペースの名前に改行(CR・LF)を禁止
inet・cidrのデフォルトのインデックスopclassがbtree_gistからGiSTに変更:btree_gist拡張でこれらの型にインデックスを作成してきた場合は確認してください
そのほか、bytea と uuid の間のキャストが許可され、バイナリで受け取ったUUIDをそのまま変換できるようになりました。
5. レプリケーションと読み取りの一貫性
シーケンス値の論理レプリケーション。 論理レプリケーションがシーケンス値も複製するようになりました。論理レプリケーションでメジャーバージョンアップグレードを行う際に、切り替え直前にシーケンス値を手作業で合わせていた作業が減ります。また、wal_level が replica であれば、サーバーを再起動せずに論理レプリケーションを有効にできます。
WAIT FOR LSNで「自分が書いたものを読む」。 書き込みはプライマリサーバーへ、読み取りはレプリカ(スタンバイ)へ送る構成では、書き込んだばかりのデータがまだレプリカに届いていないことがあります。新しい WAIT コマンドを使えば、レプリカ側で特定のWAL位置まで反映されるのを待つことができます。
-- プライマリサーバー:書き込み直後に現在のWAL位置を確認
SELECT pg_current_wal_lsn(); -- 例: 0/306EE20
-- レプリカ:その位置まで反映されてから読み取る(最大1秒待機)
WAIT FOR LSN '0/306EE20' WITH (TIMEOUT '1s');
SELECT * FROM orders WHERE id = 1001;
NO_THROW オプションを指定すると、タイムアウト時にエラーではなく状態(success、timeout など)が返されます。
6. その他の変更
- autovacuum が並列ワーカーでインデックスをクリーンアップし、最も必要性の高いテーブルから処理するスコアリング方式を導入
- jsonpathの文字列メソッドを追加:
lower()、upper()、initcap()、replace()、split_part()、btrim()・ltrim()・rtrim() - プランナーの決定を固定・制御する
pg_plan_advice拡張と、それをクエリごとに自動適用するpg_stash_advice
Erdmatesで事前にチェックする
19にアップグレードする前にスキーマをERDとしてインポートしてみると、主キーの表示がないテーブル(REPACK CONCURRENTLY を使えないテーブル)と外部キーの関係を一目で確認できます。Erdmatesは、PostgreSQLの CREATE TABLE・COMMENT ON 文をインポートしてERDとして描画します。
まとめ
PostgreSQL 19でスキーマ設計者が真っ先に押さえるべきことは3つです。すべてのテーブルに主キーを持たせて REPACK CONCURRENTLY を使えるようにすること、段階的なマイグレーションにCHECK制約の NOT ENFORCED → ENFORCED の切り替えを活用すること、そして standard_conforming_strings・json_array() のような動作の変更をアップグレード前にテストすることです。正式リリースまでは機能一覧が変わる可能性があるため、最終的なリリースノートを改めて確認してください。