PostgreSQL 18がやってくる(3) システムビューの差分

# はじめに
にゃーん

今回は、PostgreSQL 17とPostgreSQL 18devのシステムビューの差分を調べてみる。
（ここではシステムビューと「データベース活動状況の監視（Monitoring Database Activity）で説明されている``pg_stat_*``ビュー（累積統計システム）も含む）
まだbetaリリース前の版なので、今後変わっていく可能性が大きいけど、現時点の版で調査をしてみた。
なお、システムカタログの差分については、この記事とは別に調査結果をまとめている。
→[PostgreSQL18がやってくる(2) システムカタログの差分](https://qiita.com/nuko_yokohama/items/255abc19b4901e2a23a4)

## 調査方法
PostgreSQL 17とPostgreSQL 18dev(2025-03-29 commitid d6d8054dc72d4844f52f1552f8d3074c16987e32)それぞれで以下の手順を実施。

* それぞれ、データベースクラスタを新規に作成して起動する。
  * ``-U postgres``オプションと``-c "port=xxxxx"``と``-D (ディレクトリ名)``のみ指定して作成
* psqlでpostgresデータベースにログイン
* `\o` *ファイル名* メタコマンドで出力先ファイルを指定
* `\a` メタコマンドで整形用の空白が入らないようにする。
* 以下のSELECT文を実行してpsqlを終了する。

```sql
SELECT c.relname, attname, atttypid
FROM pg_class c JOIN pg_attribute a ON (a.attrelid = c.oid) JOIN pg_namespace ns ON (c.relnamespace = ns.oid)
WHERE ns.nspname = 'pg_catalog' AND c.relkind ='v'
ORDER BY c.relname, a.attname
;
```
ソートはリレーション名と属性名にする。（あえてリレーション内の属性の並び番号ではソートしない）

* psqlを終了する。
* PostgreQSL 17の検索結果ファイルと、PostgreSQL 18devの検索結果ファイルをdiffる。

# 調査結果概要
システムビューのビュー単位での新規追加はないが、既存のビューに対していくつかの列の増減があった。

|ビュー名|変更概要|
|:--|:--|
|pg_backend_memory_contexts|parent列の削除<br>path列. type列の追加|
|pg_stat_all_tables|total_analyze_time列の追加<br>total_autoanalyze_time列の追加<br>total_autovacuum_time列の追加<br>total_vacuum_time列の追加 |
|pg_stat_checkpointer|num_done列の追加<br>slru_written列の追加 |
|pg_stat_database |parallel_workers_launched列の追加<br>parallel_workers_to_launch列の追加 |
|pg_stat_io|extend_bytes列の追加<br>op_bytes列の削除<br>read_bytes列の追加<br>write_bytes列の追加 |
|pg_stat_progress_analyze|delay_time列の追加 |
|pg_stat_progress_vacuum|delay_time列の追加 |
|pg_stat_subscription_stats|confl_delete_missing列の追加<br>confl_delete_origin_differs列の追加<br>confl_insert_exists列の追加<br>confl_multiple_unique_conflicts列の追加<br>confl_update_exists列の追加<br>confl_update_missing列の追加<br>confl_update_origin_differs列の追加<br> |
|pg_stat_sys_tables|（pg_stat_all_tablesと同様）|
|pg_stat_user_tables|（pg_stat_all_tablesと同様）|
|pg_stat_al|wal_write列,wal_sync列,wal_write_time列,wal_sync_time列の削除|

# 各ビュー毎の修正内容
PostgreSQL 18devで修正が入ったシステムビューの内容を示す。

## pg_backend_memory_contexts
pg_backend_memory_contextsビューは、現在のセッションにアタッチされているサーバプロセスの全てのメモリコンテキストを表示する。（PostgreSQL 14～）
18devでは以下の変更があった。
* parent列が削除された
* path列. type列が追加された

### parent列の削除
これは[pgsql: Remove "parent" column from pg_backend_memory_contexts](https://www.postgresql.org/message-id/E1sdLx7-003nSI-4L@gemulon.postgresql.org)のコミットによるものっぽい。
後述のpath列の追加により、親列もpathで取得することが推奨されるようになったので削除されたようだ。

### path列の追加

|列名|データ型|説明|
|:--|:--|:--|
|path|int4[]|メモリコンテキストの階層構造を表す一時的な数値識別子の配列。最初の要素はTopMemoryContextで、それ以降の要素には中間の親が含まれ、最後の要素には現在のコンテキストの識別子が含まれる。|

これは[pgsql: Add path column to pg_backend_memory_contexts view](https://www.postgresql.org/message-id/E1sWolc-0015ev-Rn@gemulon.postgresql.org)のコミットによるものっぽい。

> "path"は、メモリコンテキスト間の親子関係を決定する信頼性の高い方法を提供する。 
以前は、再帰的な問い合わせを書いて 「parent 」列と 「name 」列を結合することで、信頼性の低い方法で行っていた。 
これは、名前が一意ではないため信頼性が低く、間違った親に結合してしまう可能性があった。
　
この信頼性を高めるために、path にはTopLevelMemoryContextの識別子から始まる数値識別子の配列を格納する。 
この配列には、TopLevelMemoryContextと現在のコンテキストの間にある各中間親の要素が含まれている。

運用者が直接このビューを参照することはないと思うけど、PostgreSQLのメモリ管理の中で、階層化されているメモリコンテキストの検索方法が変わった、ということなんでしょうかね。

### type列の追加

|列名|データ型|説明|
|:--|:--|:--|
|type|text|メモリコンテキストのタイプ|

これは[pgsql: Add context type field to pg_backend_memory_contexts](https://www.postgresql.org/message-id/E1sODBt-003m8B-IU@gemulon.postgresql.org)のコミットによるものっぽい。
メモリコンテキストのタイプは``AllocSet``, ``Generation``,``Slab``,``Bump``,``???"``のどれかが設定されるようだけど、個々の内容までは追跡する気力なし・・・

## pg_stat_all_tables
pg_stat_all_tablesビューは現在のデータベース内のテーブル（TOASTテーブルを含む）ごと1行の形式で、特定のテーブルへのアクセスに関する統計情報を表示する。（PostgreSQL 7.2～） 

### total_vacuum_time/total_autovacuum_time/total_analyze_time/total_autoanalyze_timeの追加

この変更は[Track per-relation cumulative time spent in [auto]vacuum and [auto]analyze](https://www.postgresql.org/message-id/E1tcZww-003vl0-1d@gemulon.postgresql.org)によるもの。
追加された4つの列を以下に示す。

|列名|データ型|説明|
|:--|:--|:--|
|total_vacuum_time |double precision |このテーブルが手動でバキュームされた合計時間（ミリ秒単位)|
|total_autovacuum_time |double precision |このテーブルがautovacuumデーモンによってバキュームされた合計時間（ミリ秒単位） |
|total_analyze_time |double precision |このテーブルが手動でANALYZEされた合計時間（ミリ秒単位） |
|total_autoanalyze_time |double precision |このテーブルがautovacuumデーモンによって分析された合計時間（ミリ秒単位） |

``pg_stat_sys_tables``および```pg_stat_user_tables``についても同じ変更が入っているが説明は割愛。


## pg_stat_database
pg_stat_databaseビューには、クラスタ内のデータベース毎に1行と加えて共有オブジェクトのための1行が含まれ、データベース全体の統計情報を示す。 （PostgreSQL 7.2～）

### parallel_workers_launched列/parallel_workers_to_launch列の追加

|列名|データ型|説明|
|:--|:--|:--|
|parallel_workers_to_launch |bigint |このデータベースのクエリによって起動される予定の並列ワーカーの数|
|parallel_workers_launched |bigint |このデータベースのクエリによって起動される並列ワーカーの数|

parallel_workers_to_launchの「起動される予定」というのは、max_parallel_workers/max_parallel_workers_per_gatherの設定によるパラレルワーカープロセスの理論上の最大値、parallel_workers_launchedは実際に起動したプロセス数なんだろうか？

この変更は[pg_stat_statements: Add columns to track parallel worker activity](https://www.postgresql.org/message-id/E1syJft-002lX5-16@gemulon.postgresql.org)で議論されたもの。

## pg_stat_ioビュー
pg_stat_ioビューには、バックエンドのタイプ、ターゲットI/Oオブジェクト、およびI/Oコンテキストの各組み合わせに対する1行が含まれ、クラスタ全体のI/O統計が示される。（PostgreSQL 16～）

PostgreSQl 18devでは、[Make pg_stat_io count IOs as bytes instead of blocks for some operations](https://www.postgresql.org/message-id/E1tXXOy-001PdI-71@gemulon.postgresql.org)により、以下の列の削除および3つの列が追加された。

ざっくり要約するとこういうことらしい。
* pg_stat_ioが一部の操作でIOをブロックではなくバイトとしてカウントするようにした。
* バイト計算のために、pg_stat_ioに読み込み、書き込み、拡張の3つの列が追加した。
* 常にBLCKSZにハードコードされていたop_bytesは削除した。 

### op_bytes列の削除
* 常にBLCKSZにハードコードされていたop_bytesは削除した。 

### extend_bytes列/read_bytes列/write_bytes列の追加
* バイト計算のために以下の3つの列が追加された。

|列名|データ型|説明|
|:--|:--|:--|
|read_bytes  |numeric |読み取り操作の合計サイズをバイト単位で表す。  |
|write_bytes  |numeric |書き込み操作の合計サイズをバイト単位で表す。  |
|extend_bytes  |numeric |リレーション拡張操作の合計サイズをバイト単位で表す。 |

追加した型はbigintではなく、numericを使っている。これはbigintの範囲を超える可能性があるからなのかな。

## pg_stat_progress_analyze/pg_stat_progress_vacuum
このビューはANALYZE処理やVACUUM処理の進捗状況を参照するビューである。（PostgreSQL 13～）
この2つのビューに、以下のコミットにより列が1つ追加された
[Add cost-based vacuum delay time to progress views.](https://www.postgresql.org/message-id/E1thyuR-006d9L-4E@gemulon.postgresql.org)

### pg_stat_progress_analyze

PostgreSQL 18devでは以下の列が追加された。

|列名|データ型|説明|
|:--|:--|:--|
|delay_time   |double precision |コストベースの遅延のためにスリープに費やされた合計時間（track_cost_delay_timingが有効な場合はミリ秒単位、そうでない場合はゼロ）。  |

### pg_stat_progress_vacuum

PostgreSQL 18devでは以下の列が追加された。

|列名|データ型|説明|
|:--|:--|:--|
|delay_time   |double precision |コストベースの遅延（セクション19.10.2参照）によるスリープ時間の合計をミリ秒単位で表わす（track_cost_delay_timingが有効な場合、それ以外は0）。<br>これには関連する並列ワーカーがスリープした時間も含まれる。ただし、並列ワーカーがスリープ時間を報告する頻度は 1 秒に 1 回以下なので、報告される値は若干古いかもしれない。 |

## pg_stat_subscription_stats
サブスクリプションごとに1行で論理レプリケーションに関する情報を表示する。（PostgreSQL 15～）

PostgreSQL 18devでは以下の7つの列が追加された。
この列の追加は[Collect statistics about conflicts in logical replication.](https://www.postgresql.org/message-id/E1slgqD-0003ah-LA@gemulon.postgresql.org)による。
内容は論理レプリケーションの変更の適用中に特定の競合タイプが発生した回数を示す列を追加したというもの。

以下に追加された7つの列を示す。
|列名|データ型|説明|
|:--|:--|:--|
|confl_insert_exists   |bigint |変更の適用中に行の挿入がNOT DEFERRABLE一意制約に違反した回数。この競合の詳細についてはinsert_existsを参照。 |
|confl_update_origin_differs |bigint |変更の適用中に、以前に別のソースによって変更された行に対して更新が適用された回数。この競合の詳細については update_origin_differs を参照。 |
|confl_update_exists    |bigint |更新された行の値が、変更適用中にNOT DEFERRABLE一意制約に違反した回数。この競合の詳細についてはupdate_existsを参照。 |
|confl_update_missing  |bigint | 変更の適用中に更新されるタプルが見つからなかった回数。この競合の詳細については update_missing を参照。|
|confl_delete_origin_differs    |bigint |変更の適用中に、別のソースによって以前に変更された行に対して削除操作が適用された回数。この競合の詳細については delete_origin_differs を参照。 |
|confl_delete_missing    |bigint |変更の適用中に削除するタプルが見つからなかった回数。このコンフリクトの詳細については delete_missing を参照。 |
|confl_multiple_unique_conflicts   |bigint |変更の適用中に、行の挿入または更新された行の値が複数のNOT DEFERRABLE一意制約に違反した回数。この競合の詳細はmultiple_unique_conflictsを参照。 |

実際に追加された7パターンの競合を発生させて、挙動を確認したいところ。

## pg_stat_wal
pg_stat_walビューは常に1行を持ち、クラスタのWALアクティビティに関するデータを含む。（PostgreSQL 14～）

### wal_write列,wal_sync列,wal_write_time列,wal_sync_time列の削除
この変更は[Remove read/sync fields from pg_stat_wal and GUC track_wal_io_timing](https://www.postgresql.org/message-id/E1tmMk9-000NUo-2M@gemulon.postgresql.org)によるもの。

このコミットの理由として以下の2つの理由が書かれている。なるほど・・・

> a051e71e28a1は、バックエンドの型、IOコンテキスト、IOオブジェクトにまたがるようになったため、より粒度の細かいpg_stat_ioにこの情報と同等のものを追加した。 そのため、pg_stat_walに同じ情報を保持してもほとんどメリットがない。

> このコミットのもう1つの利点は、PendingWalStatsを削除したことで、IO統計をすでにサポートし、WALの書き込み/同期統計データにアクセスできるバックエンドごとのWAL統計を追加する今後のパッチを単純化することである。

# おわりに
現時点ではシステムカタログ/累積統計システムのビューの差分を調査した。PostgreSQL 18でも結構変更が入りそうだ。
累積統計システムのビューの変更は、監視用のSQLへの影響もあるので要注意。