この記事は PostgreSQL 19 リリースノートのドラフトに基づいています。機能セットはベータフリーズで確定します。PG 19 がベータ・RC を経て進むにつれて、本記事も随時更新します。
| 更新履歴 | コメント |
|---|---|
| 2026/06/04 | 初版。 |
PostgreSQL 18 は非同期 I/O を素の機能として出荷しました。PostgreSQL 19 はその運用面の対になるリリースであり、以下に挙げる項目は私が最も期待しているものです。コア内のプランアドバイスは、プランナーで最も長く残っていたギャップを埋めます。DDL 抽出がコアに入ります。REPACK とチェックサムはメンテナンスウィンドウの外へ移動します。ロック競合とスタンバイのリカバリ状態は第一級のシステムビューになります。本番障害の原因となってきた 32 ビット MultiXact の上限はなくなります。autovacuum は並列化され、観測可能になります。
pg_plan_advice
PostgreSQL のプランナーは平均的なケースには優れていますが、ロングテールでは時に誤ります。歪んだ分布、古い統計情報、多数テーブルの結合は、運用上許容できないプランへとプランナーを追い込むことがあります。回避策はコアの外にありました — pg_hint_plan 拡張、アプリケーションレベルの SET enable_* フラグ、サードパーティのプランロック拡張 — それぞれ独自のセマンティクスとライフサイクルを持っていました。
2026 年 2 月、Clerk はある障害をまさにこのパターンに突き止めました — 値の 99.9996% が NULL のカラム、たまたまサンプルに NULL しか含まれなかった ANALYZE、そしてそのカラムが 100% NULL だと結論づけたプランナー。その結果生成されたプランは、17,000 行を超える非 NULL 行が存在する場所に、ゼロ行を仮定していました。
PostgreSQL 19 は、その答えを 2 層構造でコア内にもたらします。
pg_plan_advice はプランナーアドバイザーフレームワークを導入します。関連するプラン選択 — 結合順序、スキャン方式など — を捉えたプランアドバイス文字列を生成し、他のモジュールがプランニング時にアドバイスを注入できるフックを公開します。アドバイスは EXPLAIN (PLAN_ADVICE '...') でインライン渡しすることで、一回限りの用途にも使えます。
pg_stash_advice はプランアドバイス文字列を (stash_name, queryId) でキーづけして動的共有メモリに永続化し、pg_plan_advice フックを介してプランニング時に自動的に注入します。書き込みは一度。すべてのセッションで有効になります。
-- 1. 拡張をロードする (事前に shared_preload_libraries に含まれている必要がある)
CREATE EXTENSION pg_stash_advice;
-- 2. stash を作成する
SELECT pg_create_advice_stash('events_stash');
-- 3. queryId を調べる
EXPLAIN (VERBOSE) SELECT * FROM events WHERE tenant_id = 42;
-- → Query Identifier: 9876543210
-- 4. その queryId に対してアドバイスを stash する
SELECT pg_set_stashed_advice('events_stash', 9876543210,
'INDEX_SCAN(events events_tenant_idx)');
-- 5. このセッションで stash を有効化する
SET pg_stash_advice.stash_name = 'events_stash';
-- 6. 確認 — プランナーがインデックスパスを選ぶようになる
EXPLAIN (COSTS OFF) SELECT count(*) FROM events WHERE tenant_id = 42;
-- → Index Scan using events_tenant_idxスコープは pg_stash_advice.stash_name GUC で制御します — ALTER DATABASE、ALTER ROLE、またはセッションレベルの SET です。
なぜ便利か: アプリケーションを変更せずにプランを安定させられます。stash への一度の書き込みが、一致する queryId を実行するすべてのセッションで有効になり、pg_hint_plan やサードパーティツールは不要です。適切なユースケースは、本番データ上でプランナーのリグレッションが既知である少数のクエリ群です。アドバイスの適用はプランを変えない場合でもコストがかかるため、ワークロード全体に広く適用するパターンではありません。
DDL 抽出関数
PostgreSQL はこれまで、データベース・ロール・テーブルスペースの CREATE 文をカタログから取り出す手段を出荷したことがありませんでした。データはそこにあります。DDL はありません。それを必要とするチームは皆、独自の抽出器を書いてきました — pg_dump --schema-only を回すシェルループ、マイグレーションツール内の手書きカタログクエリ、カタログを直接読んで DDL を組み立てる Bytebase のようなスキーマ管理プラットフォーム。実装はばらばらです。保守の負担はそうではありません — メジャーバージョンごとに新しいカタログカラムと新しい属性エンコーディングを吸収しなければなりません。
PostgreSQL 19 は、こうした個別レイヤーを安定したコア内の関数呼び出しの契約で置き換えます。3 つの関数、1 つのオプション形状、DDL をテキストとして返します。
SELECT pg_get_database_ddl('mydb'::regdatabase);
SELECT pg_get_role_ddl('myrole'::regrole);
SELECT pg_get_tablespace_ddl('mytbs');3 つすべてが pretty := true を受け付けます。pg_get_database_ddl() はさらに owner := false と tablespace := false を受け付け、対象環境が異なる場合にそれらの句を抑制できます。
なぜ便利か: 安定したコア内の契約が、各チームの個別の抽出器を置き換えます。マイグレーションの準備、CI/CD のスキーマ差分、ロール権限やデータベースプロパティの監査スナップショット、スキーマ管理ツールからの埋め込み呼び出し — これらがすべて pg_dump の出力をパースするのをやめられます。
これらの関数は pg_dump を置き換えるのではなく補完します — 単一オブジェクトのみで、依存関係の順序付けはなく、インデックス・トリガー・制約も含みません。権限はスコープされています — データベースに対する CONNECT、テーブルスペースに対する USAGE、ロールに対してはスーパーユーザーまたは本人。
オンラインメンテナンス
長年のメンテナンスの痛点が 2 つ小さくなります。どちらも以前はウィンドウを必要としていました。
REPACK と REPACK CONCURRENTLY。 単一のコア内コマンドが VACUUM FULL、CLUSTER、そしてサードパーティの pg_repack 拡張を統合します。CONCURRENTLY を使うと、再構築は ACCESS EXCLUSIVE ロックなしで実行されます — 新しいヒープが構築・切り替えされる間、並行する読み書きが元のヒープに対して進行します。max_repack_replication_slots が並行版を支えるスロットプールを制御します。
REPACK TABLE my_table;
REPACK TABLE my_table CONCURRENTLY;
REPACK INDEX my_index CONCURRENTLY;オンラインでのデータチェックサムの有効化・無効化。 チェックサムの切り替えに、クラスタを停止して停止中のデータディレクトリに対して pg_checksums を実行する必要はもうありません。変更は稼働中のクラスタで段階的に適用されます。
なぜ便利か: どちらの項目も「ウィンドウをスケジュールして、何も壊れないことを祈る」種類の運用を取り除きます。
REPACK CONCURRENTLY は、ロジカルデコーディングに支えられたあらゆる機能と同じ注意が必要です — レプリケーションスロットを消費するため、遅いコンシューマや詰まったトランザクションが WAL を保持します。max_repack_replication_slots を妥当な上限に固定し、長い repack の間はスロットの遅延を監視してください。オンラインチェックサムの切り替えは 2 つのうち安全な方です — 失敗モードはクリーンなアボートであり、ロックアウトされたクラスタではありません。
観測可能性
19 で 2 つの診断ギャップが閉じます。ロック履歴とスタンバイのリカバリ状態が第一級のシステムビューになります。
ロック
pg_stat_lock はロック種別ごとの統計を公開します — ロックモード別に分けられたカウントと待機。pg_locks はスナップショットを示します。pg_stat_lock は履歴を示します。
log_lock_waits がデフォルトでオンになります。長いロック待機が標準でログに記録されるようになりました。しきい値とノイズフロアは変更されていません — 運用者は新しいインストールのたびに GUC を切り替える必要がなくなります。
なぜ便利か: この組み合わせは、どちらか一方単独よりも重要です。pg_locks は「今この瞬間に誰がブロックされているか」に答えます。pg_stat_lock は「時間をかけて競合がどこに集中しているか」に答えます。前者は即時の介入の判断材料になります。後者はスキーマとインデックスの設計判断の材料になります。pg_stat_lock をリレーションとモードでフィルタしたダッシュボードクエリを組んでみてください — 競合の意外性のほとんどは、2 〜 3 のホットテーブルに収まります。
リカバリ
スタンバイの監視は関数を順に呼ぶことを意味していました — pg_last_wal_replay_lsn()、pg_last_wal_receive_lsn()、pg_get_wal_replay_pause_state()、pg_last_xact_replay_timestamp() — そしてその結果を突き合わせる必要がありました。各呼び出しはそれぞれ別のスナップショットでした。「このスタンバイは今どこにいるのか?」への答えは、一つの読み取りではなく合成物でした。
PostgreSQL 19 は pg_stat_recovery を追加します。これはそのすべてを共有メモリから一度の読み取りでスナップショットする単一のシステムビューです。フィールドは以下をカバーします。
- 最後にリプレイされた WAL の位置とタイムライン
- 現在リプレイ中の WAL レコードの終了位置とタイムライン
- 現在の WAL チャンクの開始時刻
- 昇格トリガーの状態
- 最後のコミット / アボートのタイムスタンプ — レプリケーション遅延の鮮度シグナル
- リカバリの一時停止状態
SELECT * FROM pg_stat_recovery;このビューはプライマリでは行を返しません。読み取りアクセスには pg_read_all_stats ロールが必要です。
なぜ便利か: アトミックなスナップショットこそが肝心な部分です。以前は「レプリカが遅れすぎている」というアラートが発火したとき、本物の遅延を状態遷移と競合したクエリと区別するには、複数の関数呼び出しにまたがってタイムスタンプを相関させる必要がありました。一つのビューがそれを、ダッシュボードとランブックのための一貫した読み取りに圧縮します。現在の WAL チャンク開始時刻のフィールドには従来の関数の同等物がありません — レコード間ではなくレコードの途中で詰まったスタンバイを診断します。
ロジカルレプリケーション: シーケンス同期
ロジカルレプリケーションは 10 以来、テーブルデータを忠実に複製してきました。しかし SERIAL と IDENTITY カラムを支えるシーケンスは複製してきませんでした。サブスクライバーをプライマリに昇格させると、次の INSERT で、アプリケーションが自分のものだと思っていた行に対して主キー違反が起きます。
PostgreSQL 19 はこのギャップを閉じます。パブリケーションがシーケンスサポートを得て、新しい REFRESH SEQUENCES サブコマンドがコピーをトリガーし、sequencesync ワーカーが作業をバッチ処理します。
CREATE PUBLICATION upgrade_pub FOR ALL TABLES, ALL SEQUENCES;
ALTER SUBSCRIPTION upgrade_sub REFRESH SEQUENCES;pg_subscription_rel.srsubstate がシーケンスごとの進捗を公開します (i = INIT、r = READY)。
なぜ便利か: ゼロダウンタイムのアップグレードとフェイルオーバーがより安全になります。挙動上の注意点は、シーケンスが同期されるのは REFRESH SEQUENCES が実行されたときだけだということです — 継続的に追跡するわけではありません。この呼び出しをカットオーバーのランブックに、サブスクライバーを昇格させる直前に組み込んでください。pg_subscription_rel のクエリパターンを含むより深いウォークスルーは、Postgres 19 機能プレビュー: ロジカルレプリケーションのシーケンス同期を参照してください。
MultiXact の上限、撤廃
PostgreSQL はトランザクション間で共有される行レベルのロックを MultiXact 構造で追跡します。メンバー配列へのポインタ — MultiXactOffset — は 32 ビットで、メンバー総数を約 40 億に制限していました。トランザクション ID の周回は広く知られ、広く監視されています。MultiXact メンバーの枯渇はそうではありません。標準的な XID 消費のダッシュボードには現れません。外部キーを持つ高並行ワークロードは、数年ではなく数日でこれにぶつかることがあります。
2025 年 5 月、Metronome はデータ移行中にまさにこの上限から 4 件の別々の障害を経験し、30TB のクラスタに対して数時間の緊急バキュームを要しました。
PostgreSQL 19 は MultiXact メンバーを 64 ビットに拡張します。上限はなくなりました — 引き上げたのではなく、撤廃されました。
なぜ便利か: メンバー枯渇に対する「バキュームせよ、さもなくば死」という緊急事態はなくなりました。MultiXact メンバー空間に対して特に走っていた積極的なアンチ周回バキュームはもう不要です。ディスク回収のためのルーチンのバキュームは依然として重要です。19 へのアップグレードは pg_upgrade を介して pg_multixact SLRU ファイルを自動的に書き換えます。multixact 履歴が大きいクラスタでは、それに応じてアップグレードウィンドウを見積もってください。詳しい背景と Metronome のインシデント分析は、Postgres 19 機能プレビュー: 64 ビット MultiXactOffsetを参照してください。
バキューム
長年の不満が 2 つ同時に着地します。autovacuum が並列ワーカーを使えるようになります。pg_stat_* ビューが、遅いバキュームの診断がもう当て推量に頼らずに済むだけの状態を公開します。
並列 autovacuum。 autovacuum_max_parallel_workers が autovacuum 実行時の並列インデックス処理を有効にします。テーブルごとのチューニングは新しい autovacuum_parallel_workers ストレージパラメータにあります。手動の VACUUM (PARALLEL N) は 13 以来動作してきましたが、autovacuum はずっとシングルスレッドでした。
autovacuum の優先度が可視化された。 pg_stat_autovacuum_scores が、なぜあるテーブルが別のテーブルより先にキューに入るのかを公開します。autovacuum_*_score_weight GUC の一群 (freeze、vacuum、vacuum-insert、multixact-freeze、analyze の各圧力をカバー) が、優先度関数のチューニングを可能にします。19 より前は、autovacuum は発見順にテーブルを選んでいました。チューニングはしきい値を変えて祈ることに等しいものでした。
pg_stat_progress_vacuum に 2 カラム追加。 started_by は manual / autovacuum / autovacuum_wraparound を区別します。mode は normal / aggressive / failsafe を区別します。ルーチンの掃き掃除か緊急かが、1 カラムでわかります。
計画された並列ワーカー数と起動された数がログに記録される。 VACUUM (VERBOSE) の出力と autovacuum のログに 2 つの数値が加わります — 操作が計画した並列ワーカー数と、実際に起動した数。この 2 つはしばしば乖離します。max_parallel_maintenance_workers、min_parallel_index_scan_size、対象となるインデックス数、実行時のワーカー可用性のすべてが数をゲートします。19 より前は、起動数が計画数を下回ったとき、どのゲートが閉じたのかを示すログ証拠はありませんでした。
なぜ便利か: 重くインデックスされたテーブルでの autovacuum が高速になり、それが期待どおり実行されたかを検証するフィードバックループも得られます。並列 autovacuum は手動の VACUUM (PARALLEL N) と同じ条件でゲートされるため — 対象インデックス数、min_parallel_index_scan_size、利用可能なワーカースロット — ワーカーが実際に起動するかを検証してください。
調査の順序も変わります。古いループ — maintenance_work_mem を上げ、autovacuum_vacuum_cost_delay を下げ、祈る — は、入力が観測できないため当て推量でした。新しい手順:
pg_stat_autovacuum_scoresを読んで優先度を確認する。- autovacuum のログで計画ワーカー数と起動ワーカー数を確認する。ギャップが大きければ、ボトルネックはスループットではなくゲーティングです。
pg_stat_progress_vacuum.modeでfailsafeイベントを監視する。failsafe のクラスタは、より多くのワーカーではなく優先度の重みのチューニングを必要としています。
おわりに
pg_plan_advice は私が最も期待しているもので、Oracle や SQL Server との長年のギャップをもう一つ埋めます。pg_plan_advice はプランナーアドバイスを注入するためのコア内フックを定義します。これは、まともな SQL Plan Management (SPM) モジュールを構築できる土台です — 自動ベースラインキャプチャ、プランの進化、リグレッション検出、Oracle SPM や SQL Server の Query Store のユーザーが何年も当然のものとしてきた要素群。PostgreSQL 19 は SPM そのものを出荷するわけではありませんが、初めて、プランナーをフォークせずにコミュニティがそれを構築できる基盤を出荷します。
残りのリストは、PostgreSQL を本番で先頭に立たせ続ける、地道で苦労して得られた進歩の類です。バキュームと MultiXact は同じ(議論の余地のある) アーキテクチャ上の選択が別々の問題として表面化したものです — MVCC を実装するために、PostgreSQL は UPDATE が触れるすべての行の別バージョンを保持し、バックグラウンドプロセスがそれらを片付けます。OrioleDB のような何か — タプルを複製する代わりに undo ログ経由で MVCC を実装するストレージエンジン — がコアに着地するまで、私たちはダクトテープを貼り続けることになります。
参考文献
- Postgres 19 release notes draft
- The Part of PostgreSQL We Hate the Most
- Clerk: クエリプランの反転が引き起こした 2026 年 2 月の障害ポストモーテム
- Metronome: 2025 年 5 月の PostgreSQL MultiXact メンバー枯渇