PostgreSQL 15がやってくる(1) 設定パラメータの差分

# はじめに
にゃーん。
いつものように、PostgreSQL新バージョンの差分先行調査の時期になりました。
ということで、今回はPostgreSQL 14とPostgreSQL 15の設定パラメータの差分を調べてみる。

# 調査方法
* PostgreSQL 14/PostgreSQL 15 beta1を使って、以下の操作を実行。
  * initdb（-Dオプションと-U postgresオプションのみ指定）を実行。
  * 生成されたデータベースクラスタを起動。
  * postgresユーザでpostgresデータベースにログイン。
  * psqlの\aメタコマンドを実行。
  * psqlの\oオプションで出力ファイルを指定。
  * ``SELECT name, setting, unit, category, context, vartype, min_val, max_val, enumvals FROM pg_settings ORDER BY name;``を実行。[^1]
  * 生成されたPostgreSQL 14の結果とPostgreSQL 15-beta1の結果をdiffる。

# 調査結果
## 行数
SELECT文の行数(rows)

|version|rows|
|:--|--:|
|PostgreSQL 14|344|
|PostgreSQL 15 beta1|353|


## 差分
PostgreSQL 14.3とPostgreSQL 15 beta1の設定パラメータ差分のサマリを以下に示す。
追加されたパラメータも結構多い。

|パラメータ名|差分種別|差分概要|
|:--|:-:|:--|
|allow_in_place_tablespaces|追加|テーブルスペースをpg_tblspc内のディレクトリとして作成を許容かどうか|
|archive_library|追加|アーカイブ用のライブラリを指定する|
|compute_query_id|変更|値域にregressが追加|
|enable_group_by_reordering|追加|GROUP BY句のキーの並べ替えを有効または無効にする|
|hash_mem_multiplier|変更|デフォルト値が1.0から2.0に変更|
|log_autovacuum_min_duration|変更|デフォルト値が-1から60000に変更|
|log_destination|変更|値域にjsonlogが追加|
|log_checkpoints|変更|デフォルト値がoffからonに変更|
|log_startup_progress_interval|追加|startup process中に長時間かかった処理をロギングする間隔を設定|
|recovery_prefetch|追加|リカバリ時にブロックのプリフェッチを試みるか|
|recursive_worktable_factor|追加|再帰的な問い合わせの作業テーブルサイズの推定値算出係数|
|shared_memory_size|追加|主共有メモリ領域のサイズを報告し、最も近いメガバイトに切り上げる（？）|
|shared_memory_size_in_huge_pages|追加|主共有メモリ領域で必要とされるhugeページの数を報告|
|stats_temp_directory|削除||
|stats_fetch_consistency|追加|累積統計値がトランザクション内で複数回アクセスされる場合の動作を決定|
|track_activities|変更|Categoryの変更|
|track_activity_query_size|変更|Categoryの変更|
|track_counts|変更|Categoryの変更|
|track_functions|変更|Categoryの変更|
|track_io_timing|変更|Categoryの変更
|track_wal_io_timing|変更|Categoryの変更|
|wal_compression|変更|型の変更<br>値域の変更<br>圧縮方式追加に対応したもの。|
|wal_decode_buffer_size|追加|WALをプリフェッチするときにどこまで見るか|


# 追加されたパラメータ
PostgreSQL 15では結構多くのパラメータの追加がある。

## allow_in_place_tablespaces
カテゴリは「Developer Options」である。
テーブルスペースをpg_tblspc内のディレクトリとして作成を許容かどうかを制御するパラメータ。
デフォルト値はoffになっている。
このパラメータの説明を読むと、同一サーバ上にプライマリサーバとスタンバイサーバを配置してテストするシナリオのときに使うようだ。
通常の運用では、同一サーバ上にプライマリサーバとスタンバイサーバを配置するHA構成は設計しないと思うので、まあ使うことはないかも。

手元の1台の環境でレプリケーションに関するちょっとしたテストをするようなときに、思い出せば良いパラメータなのかな。


## archive_library
カテゴリは「Write Ahead Log」である。
``archive_command``の代わりにアーカイブ用のライブラリを指定するものっぽい。
デフォルト値は空文字列。
空文字列が設定された場合には、従来どおり、アーカイブするために``archive_command``を使うということかな。

## enable_group_by_reordering
カテゴリは「Query Planning」である。
GROUP BY句のキーの並べ替えを有効または無効にするパラメータ。
デフォルト値は``on``になっている。

このパラメータはリリースノートの以下の項目に関連している。

> Allow GROUP BY sorting to optimize column order (Dmitry Dolgov, Teodor Sigaev, Tomas Vondra)
This optimization can be disabled using the server variable enable_group_by_reordering.

これは実際にGROUP BYソートを含むクエリを動かして確認しないと効果がわからないな・・・。

## log_startup_progress_interval
カテゴリは「Error Reporting and Logging」である。
PostgreSQLのstartup process中に長時間かかった処理をロギングできるようになったっぽい。
デフォルト値は10000(ms)＝10(秒)で、-1に設定することでこのロギングを無効にできる。
パラメータの説明をみると、これはインターバルを設定するものなので、例えば10000を設定した場合、起動プロセス中のなんかが25秒かかるときには、2回ロギングされるものらしい。

実運用時に起動プロセスが10秒もかかるようなケースってどのくらいあるんだろう・・・？
本体機能ではなく、PostgreSQL本体の起動と合わせて一緒に起動する拡張機能のワーカーがバグっていたりするときなんかで役に立つのかしらん。

## recovery_prefetch
カテゴリは「Write Ahead Log」である。
WALを用いたリカバリ時に、WALセグメントファイル内で参照されるブロックのうち、まだバッファプールにないブロックのプリフェッチを試みるかどうかを制御するものらしい。
型はenum。
値域はon, off, try(デフォルト値)

tryは「try は、オペレーティングシステムが posix_fadvise 関数を提供する場合にのみプリフェッチを有効にする」ものらしい。
OSがposix_fadvise 関数を提供していない環境でonにしたらエラーになっちゃうのかな？

## recursive_worktable_factor
カテゴリは「Query Planning」である。
パラメータの冒頭の説明

> Sets the planner's estimate of the average size of the working table of a recursive query, as a multiple of the estimated size of the initial non-recursive term of the query. 

「再帰的な問い合わせの作業テーブルの平均サイズを、問い合わせの最初の非再帰的な項の推定サイズの倍数として、プランナの推定値を設定する」
を読んだけど、今ひとつよくわからない。

目的として、グラフデータの最短パス探索のような再帰的なクエリを実行するときに調整すると良いのだろうか。
先日ちょっとだけ調べた、[Apache AGE](https://qiita.com/nuko_yokohama/items/ce109bb6ff79c21bfe6f)みたいな拡張機能を使う時に効果を発揮したりするのかな？

## shared_memory_size
カテゴリは「Preset Options」である。基本的にはチューニングできないパラメータだ。
「主共有メモリ領域のサイズを報告し、最も近いメガバイトに切り上げる。」という説明に読めるのだが、一体なんのことを言っているのかわからない。

そして、デフォルト値は143という謎の数字である。なんだこの数は・・・？
ということで、このパラメータについては、今のところ良くわからないのが正直なところ・・・。

## shared_memory_size_in_huge_pages
カテゴリは「Preset Options」である。基本的にはチューニングできないパラメータだ。

説明を読むと、「指定された huge_page_size に基づいて、主共有メモリ領域で必要とされるhugeページの数を報告する。hugeページがサポートされていない場合、これは-1になる」とのこと。
今回調査した環境(Amazon Linux2)では、デフォルト値は72になっていた。
この値は、configureしたときに決まるのだろうなあ・・・。

## stats_fetch_consistency
カテゴリは「Run-time Statistics」である。
累積統計値がトランザクション内で複数回アクセスされる場合の動作を決定する。
型はenum。
値域は以下。

|値|説明|
|:--|:--|
|none|共有メモリからカウンタを再フェッチする。|
|cache|デフォルト値。<br>pg_stat_clear_snapshot()が呼び出されない限り、オブジェクトの統計情報へのアクセスは、トランザクションが終了するまでそれらの統計情報をキャッシュする。|
|snapshot|pg_stat_clear_snapshot()が呼び出されない限り、統計情報アクセスは、トランザクションが終了するまで、現在のデータベースでアクセス可能な全ての統計情報をキャッシュする。|

うーん、cacheとsnapshotの違いはキャッシュされるものの範囲の違いなのかな。
なんか検証するのが面倒そうなパラメータだな・・・。

## wal_decode_buffer_size
カテゴリは「Write Ahead Log」である。
プリフェッチするブロックを探すために、サーバーが WAL のどこまで先を見ることができるかの制限値。このパラメータは、PostgreSQL 15から追加された``recovery_prefetch``パラメータと関連している。
この値が単位なしで指定された場合、バイトとして扱われれる。
デフォルトは 512kB (=524288)になっている。

# 変更されたパラメータ
## compute_query_id
値域に``regress``が追加された。
``compute_query_id``の値域を以下に示す。

|値域|意味|
|:--|:--|
|auto|デフォルト値。<br>pg_stat_statementsなどのモジュールで自動的に有効にする。|
|off|常に無効にする。|
|on|常に有効にする。|
|regress|自動回帰テストを容易にするためにEXPLAIN出力に問い合わせ識別子を表示しないこと以外はautoと同じ効果を持つ。<br>この値域が以前のメジャーバージョンにもバックポートされたのは、リグレッションテストがokにならない、といった問題があったからなのだろうか。|

実はこの値域の追加は最近のマイナーバージョンアップリリース(例: PostgreSQL 14.3)にもバックポートされている。[^2]
（そのため、PostgreSQL 14.3とPostgreSQL 15beta1との比較では検出できなかった・・・）

|バージョン|値域|
|:--|:--|
|PostgreSQL 14.2|auto,on,off|
|PostgreSQL 14.3|auto,regress,on,off|
|PostgreSQL 15 beta1|auto,regress,on,off|

## hash_mem_multiplier
デフォルト値が1.0から2.0に変更された。

ハッシュベースのオペレーションが使用できるメモリの最大量を計算するために使用されるもの。
work_mem に hash_mem_multiplier を掛けたものである。PostgreSQL 15からのデフォルト値は 2.0 で、この場合、ハッシュ演算は通常の work_mem の 2 倍のメモリを使うことになる。

このパラメータはPostgreSQL 13から追加されたパラメータなんだけど、実は自分ではきちんとチューニングしたことがない・・・。

## log_destination
値域にjsonlogが追加された。
名前のとおりサーバログをJSON形式で出力するもの。
JSON形式で出力するためには、``logging_collector``をonにする必要がある。
JSON形式のファイルの出力先は、デフォルトだと、``log/postgresql.json``になる。
JSON形式のサーバログはこんな感じになる。

```json
{"timestamp":"2022-05-22 09:15:50.883 JST","pid":21357,"session_id":"628980b6.536d","line_num":5,"session_start":"2022-05-22
09:15:50 JST","txid":0,"error_severity":"LOG","message":"database system is ready to accept connections","backend_type":"post
master","query_id":0}
{"timestamp":"2022-05-22 09:17:24.220 JST","user":"postgres","dbname":"postgres","pid":21376,"remote_host":"[local]","session
_id":"628980e6.5380","line_num":1,"ps":"SELECT","session_start":"2022-05-22 09:16:38 JST","vxid":"3/6","txid":0,"error_severi
ty":"ERROR","state_code":"42703","message":"column \"hoge\" does not exist","statement":"SELECT hoge;","cursor_position":8,"a
pplication_name":"psql","backend_type":"client backend","query_id":0}
```
人間視点での可読性は良くないが、サーバログをプログラムで処理する場合には楽になりそう。
（jsonlogの出力形式については、別途説明記事で補足予定）

## log_autovacuum_min_duration
デフォルト値が-1から60000(ms)に変更された。
-1は自動バキュームで時間がかかったときのロギングを無効にするものだったが、15からはデフォルトで60秒を超える場合にはロギングされるようになったようだ。

## log_checkpoints
デフォルト値がoffからonに変更された。
性能問題が発生したときに、チェックポイントが関連していないかサーバログを見て確認することがあるが、解析しようとしてもチェックポイント関連のログが出ていないからわからぬ、というケースもあったりするので、デフォルトでこれがonになることで、そういう悲しい事態が回避されるかもしれない。

## track_*
デフォルト値等の変更はなし。
変数のカテゴリ(category)が変更されたのみである。
|バージョン|カテゴリ|
|:--|:--|
|PostgreSQL 14|Statistics / Query and Index Statistics Collector|
|PostgreSQL 15|Cumulative Query and Index Statistics|

対象の変数は以下の6つ。
* track_activities
* track_activity_query_size
* track_counts
* track_functions
* track_io_timing
* track_wal_io_timing

## wal_compression
型がbooleanからenumに変更された。
また、値域も以下のように変更された。

|値域|バージョン|説明|
|:--|:--|:--|
|off|PostgreSQL 14<br>PostgreSQL 15|デフォルト値。<br>圧縮を行わない。|
|on|PostgreSQL14<br>PostgreSQL 15|圧縮を行う。これが指定された場合、pglzが指定されたものと同義となる。[^3] |
|pglz|PostgreSQL 15|pglz方式（PostgreSQLデフォルトの圧縮方式）による圧縮を行う。|
|lz4|PostgreSQL 15|lz4方式による圧縮を行う。<br>この指定は``--with-lz4``指定つきでconfigure＆ビルドされた場合に有効となる。|
|zstd|PostgreSQL 15|zstd方式による圧縮を行う。<br>この指定は``--with-zstd``指定つきでconfigure＆ビルドされた場合に有効となる。|

このパラメータはfull_page_writesがonの時、またはベースバックアップ中にWALに書き込まれたフルページイメージを圧縮するかどうかを制御するものだが、PostgreSQL 14から導入されたTOAST圧縮方式の追加（pglzだけでなく、lz4も対応するようになった）の延長に当たるもので、対象がWALのフルページイメージにも拡張された、というものっぽい。[^4]


# 削除されたパラメータ
## stats_temp_directory
とくに詳細な理由は書いてないけど、PostgreSQL 15で削除されたもよう。

> Remove unnecessary server variable stats_temp_directory (Andres Freund, Kyotaro Horiguchi)

このパラメータは、一時的な統計データを格納するディレクトリを設定するもので、デフォルト値は``pg_stat_tmp``（データベースクラスタ内の相対パス）だった。
これをチューニング可能にしていたのは、

> RAMベースのファイルシステムを指定することで、物理的なI/O要件が減少し、性能が向上する可能性があります。

という話があったからなんだけど、PostgreSQL 15の開発中に、それほど効果はない、というで削除されたのだろうか・・・（hacker-mlまでは追ってない）。

# おわりに
PostgreSQL 15でも多くの設定パラメータの変更があるようだ。
今回の記事は机上調査でしかないので、今後、各機能を実際に動かしてみてどういう新機能が追加されたのかを確認していきたい。
また、この調査結果はあくまでもbeta1時点のものなので、今後開発が進んでbeta2以降で変更される可能性もある。beta2以降がリリースされたから再確認しようと思う。

[^1]: enum値の値域の差分というパターンがあるので、enumvalsをSELECT句に追加した。指摘してくれた[nori_shinoda](https://twitter.com/nori_shinoda)さんに感謝。
[^2]: これが取り込まれたときのcommitid:[ebf6c5249b7db525e59563fb149642665c88f747](https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=ebf6c5249b7db525e59563fb149642665c88f747&fbclid=IwAR0onRVZ9cxJFVH3S-6hVdmKW_aVDi2-WAXl9suO4YyGtLRk7rTW__yOvh4)
この件は[nori_shinoda](https://twitter.com/nori_shinoda)さんに教えてもらいました。
[^3]: `./backend/utils/misc/guc.cをチラ見してそう判断した。なお、on/offだけでなく、ture/false, yes/no, 1/0 も値域として実は許容しているように見える。
[^4]: このパラメータを調べて、PostgreSQLではzstd方式の圧縮も使えるようになったのを知った。ということはTOAST圧縮についても新たな選択肢が増えたってことかな？