【JPUG主催】PostgreSQLカンファレンス2020【11月13日開催】
他のバージョンの文書 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

11.3. WALの設定

データベースの性能に影響するようなWALに関連したパラメータがあります。この節では、その使い方を説明します。設定方法の詳細についてはSection 3.4を参照してください。

WALには2つの共通関数があります。 LogInsertLogFlushです。 LogInsertは共有メモリ上のWALバッファに新しいレコードを挿入します。新しいレコードを挿入する余地がないときは、LogInsertは、満杯になったWALを書き込み(カーネルキャッシュに移動)しなければいけません。これは望ましいことではありません。なぜなら、データベースへの低レベルの変更(たとえばタプルの挿入)のたびにLogInsertが呼ばれますが、そのような場合には変更を受けたページに対して排他ロックがかかっており、それ故この操作は可能な限り高速に実行されなければなりません。さらに悪いことには、WALバッファへの書き込みの際に、さらに時間がかかる、強制的な新しいログセグメントの生成が必要となるかもしれません。通常、WALの書き込み、吐き出しはLogFlush要求で実施されます。これはたいていの場合、トランザクションコミットの際に永続的な記憶領域にトランザクションレコードが吐き出されることを保証するために行われます。ログ出力が大量に行われるシステムでは、LogInsertWALバッファの書き込みを行うことを防ぐほどにはLogFlush要求が頻繁に起らないかもしれません。そういうシステムでは、postgresql.confWAL_BUFFERS変数を変更してWALバッファの数を増やしてください。デフォルトのWALバッファの数は8です。この数を増やすと共有メモリの使用量に影響があります。

チェックポイントは、一連のトランザクションにおいて、それ以前にログされたすべての情報でデータファイルが更新されていることが保証されている時点を指します。チェックポイントでは、すべての変更されたデータページがディスクに吐き出され、特別なチェックポイントレコードがログファイルに書き込まれます。その結果、クラッシュが発生した際に、ログの中でどのレコード(これはredoレコードと呼ばれています)から復旧処理がREDOログ操作を開始すべきかを知ることができます。なぜなら、redoレコード以前にデータファイルに対して行われた変更はすでにディスク上に記録済みだからです。チェックポイントが実施された後、undoレコード以前のすべてのログセグメントは不要となり、削除、または再利用することができます。(WAL ベースの BAR が実装された時、このログセグメントは削除もしくは再利用される前に保存されることになります。)

また、チェックポイント作成処理では、将来の使用を目的とした、数個のログセグメントを作成することもできます。これにより、 LogInsertLogFlush によるログセグメント作成に要する処理時間を短縮することができます。(これが実行されると、その作成のためにデータベースシステム全体が遅くなります。ですので、チェックポイント作成処理にて、他に致命的な影響を与えることなく、そのファイルを作成できれば、より好ましいです。)デフォルトでは、現在のセグメントの 75 % が使用された場合にのみ、16 Mバイトのセグメントファイルが新規に作成されます。チェックポイントの間に 4Mバイト 以上のログ出力を行うシステムでは不適切です。 WAL_FILES 設定パラメータを変更して、チェックポイント時に最大64ログセグメントを前もって作成するようにサーバを設定することができます。

postmasterは次のチェックポイントを作成する時に毎回特別なバックエンドを起動します。 CHECKPOINT_SEGMENTSログセグメント数に達するか、またはCHECKPOINT_TIMEOUT秒が経過するか、どちらかの条件が満たされるとチェックポイントが作成されます。デフォルトの設定では、それぞれ3セグメントと300秒となっています。また、CHECKPOINT SQL コマンドで強制的にチェックポイントを作成することもできます。

CHECKPOINT_SEGMENTSCHECKPOINT_TIMEOUT、またはその両者を減少させると、チェックポイントはより頻繁に行われます。これにより、(再処理に要する時間がより少なくなりますので、)クラッシュ後の修復は高速になります。しかし、より頻繁に行われるようになる、変更されたデータページの吐き出しにより増大するコストとバランスを考えなければなりません。更に、データページの一貫性を保証するために、各チェックポイント後の最初に変更されるデータページは、そのページ全体の内容がログに保存されることになります。このように、チェックポイントの間隔を少なくすることは、ログへの出力を増加させ、間隔を短くする目的の一部を無意味にします。また、確実により多くのディスクI/O が発生します。

16M バイトのセグメントファイル数は、常に少なくとも WAL_FILES + 1 あり、通常は WAL_FILES + MAX(WAL_FILESCHECKPOINT_SEGMENTS) + 1 を越えません。WAL で必要とする領域の推定に、これを使用することができます。普通、古いセグメントファイルが不要になった時、それらは再利用(将来順番に使われるセグメントとなるように名前が変更)されます。短時間のログ出力のピークのためにセグメントファイル数が WAL_FILES + MAX(WAL_FILES, CHECKPOINT_SEGMENTS) + 1 を越えた場合、システムがこの上限以下になるまで、不要になったセグメントファイルを再利用するのではなく、削除します。(通常状態でもこれが発生するようであれば、防止するために WAL_FILES を増やさなければなりません。後で再度作成する必要があるログセグメントの削除はもったいなく、意味がありません。)

COMMIT_DELAYパラメータにより、LogInsertがコミットレコードをログに書き込んでからLogFlushが行われるまでの間にバックエンドが何マイクロ秒sleepするかが決まります。この遅延があることにより、ほかのバックエンドがコミットレコードをログに書き込んだあと、それらすべてのログレコードを1回のログ同期で吐き出すことができます。 fsync が無効な場合や、COMMIT_SIBLINGSよりも少ない数のバックエンドしか現在アクティブなトランザクションに存在しない場合は、sleepしません。このことにより、すぐにコミットしそうなバックエンドがいないときでもsleepするのを防ぐことができます。たいていのプラットフォームでは、sleepの最小単位はミリ秒であることに注意して下さい。ですから、0以外のCOMMIT_DELAYの設定は、1マイクロ秒から10,000マイクロ秒まで効果は同じことになるでしょう。これらのパラメータの適切な値はまだ明確ではありません。実験が必要です。

WAL_SYNC_METHODパラメータはPostgreSQLがカーネルに対してWAL更新のディスクへの書き込みを依頼する方法を決定します。どういう設定でも信頼性は同じはずですが、プラットフォームによってどれが一番早いかは全然違います。ちなみに、このパラメータはFSYNCが無効になっている場合は役に立ちません。

WAL_DEBUGを0以外の値にすることで、LogInsertLogFlushWALにおける呼び出しが標準エラー出力に出力されるようになります。いまのところ、値による違いはありません。将来はもっと汎用的な方法に置き換えられるかもしれません。