★PostgreSQLカンファレンス2024 12月6日開催/チケット販売中★
他のバージョンの文書 16 | 15 | 14 | 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

24.1. 定常的なバキューム作業

PostgreSQLデータベースはバキューム処理として知られている定期的な保守を必要とします。 多くのインストレーションでは、24.1.6で説明されている自動バキュームデーモンでのバキューム処理を行わせることで充分です。 それぞれの状況に合った最善の結果を得るため、そこで説明する自動バキューム用パラメータの調整が必要かもしれません。 データベース管理者によっては、cronもしくはタスクスケジューラスクリプトに従って典型的に実行される、手作業管理のVACUUMコマンドによりデーモンの活動を補足したり、置き換えたりすることを意図するかもしれません。 手作業管理のバキューム処理を適切に設定するためには、以下のいくつかの小節で説明する問題点を理解することが必須です。 自動バキューム処理に信頼をおいている管理者にとっても、この資料に目を通すことはそれらの理解と自動バキューム処理の調整に役に立つことでしょう。

24.1.1. バキューム作業の基本

PostgreSQLVACUUMコマンドは以下の理由により定期的にそれぞれのテーブルを処理しなければなりません。

  1. 更新、あるいは削除された行によって占められたディスク領域の復旧または再利用。
  2. PostgreSQL問い合わせプランナによって使用されるデータ統計情報の更新。
  3. 可視性マップの更新。 これによりインデックスオンリースキャンが高速化される。
  4. トランザクションIDの周回またはマルチトランザクションIDの周回による非常に古いデータの損失を防止。

以降の小節で説明するように、これらの理由の1つ1つはVACUUM操作の実行について、その頻度の変動や対象領域の変動に影響します。

VACUUMには、標準VACUUMVACUUM FULLという2つの種類があります。 VACUUM FULLはより多くのディスク容量を回収することができますが、実行にとても時間がかかります。 また、VACUUMの標準形式は実運用のデータベースに対する操作と同時に実行させることができます。 (SELECTINSERTUPDATEDELETEなどのコマンドは通常通りに動作し続けます。 しかし、バキューム処理中はALTER TABLEなどのコマンドを使用してテーブル定義を変更することはできません。) VACUUM FULLはそれが作用する全てのテーブルに対し排他ロックを必要とするので、それらテーブルのその他の用途と並行して行うことはできません。 一般的に、管理者は標準VACUUMの使用に努め、VACUUM FULLの使用を避けるべきです。

VACUUMは、かなりの量のI/Oトラフィックを発生させます。 このため、他の実行中のセッションの性能を劣化させる可能性があります。 バックグラウンドで実行されるバキューム処理による性能への影響を軽減させることを調整できるような設定パラメータがあります。 19.4.4を参照してください。

24.1.2. ディスク容量の復旧

PostgreSQLでは、行のUPDATEもしくはDELETEは古い行を即座に削除しません。 この方法は、多版同時性制御(MVCC第13章を参照してください)の恩恵を受けるために必要なものです。 あるバージョンの行は他のトランザクションから参照される可能性がある場合は削除されてはなりません。 しかし最終的には、更新された前の行や削除された行を参照するトランザクションはなくなります。 必要なディスク容量が無制限に増加しないように、これらが占める領域は、新しい行で再利用できるように回収されなければなりません。 これはVACUUMを実行することで行われます。

標準形式のVACUUMは、テーブルとインデックス内の不要な行を削除し、その領域を将来の再利用が可能であるものとして記録します。 しかし、その領域をオペレーティングシステムに返却することはありません。 例外として、テーブルの末尾に完全に空のページが存在し、かつそのテーブルの排他ロックが容易に獲得できるような特殊な場合には、その領域を返却します。 対照的にVACUUM FULLは、不要な領域のない全く新しいバージョンのテーブルファイルを書き出すことで、積極的にテーブルを圧縮します。 テーブルの容量を最小化しますが、長い時間がかかる可能性があります。 また操作が終わるまで、テーブルの新しいコピー用に余計なディスク領域を必要とします。

定常的なバキューム作業の通例の目安はVACUUM FULLの必要性を避けるに充分な頻度で標準VACUUMを行うことです。 自動バキュームデーモンはこのようにして作動を試みます。 そして実際VACUUM FULLを行いません。 この手法において、その発想はテーブルを最小サイズに保つのではなく、ディスク領域使用の安定状態を保持することです。 それぞれのテーブルは、その最小サイズにバキューム作業とバキューム作業の間で使用されることになる容量を加えたのに等しい空間を占有します。 VACUUM FULLは、テーブルをその最小サイズまで縮小し、ディスク空間をオペレーティングシステムに返却するために使用することができますが、もし将来そのテーブルが再び肥大化するのであれば、大した意味がありません。 従って、程よい頻度の標準VACUUMを実行するほうが、不定期のVACUUM FULLを実行するより大量の更新テーブルを保守するにはより良い取り組みとなります。

例えば負荷が少ない夜間に全ての作業を行うように、一部の管理者は自身で計画したバキューム作業の方を選びます。 固定したスケジュールに従ってバキューム作業を行うことについての問題は、もし更新作業によりテーブルが予期せぬ急増に遭遇した場合、空き領域を回収するためにVACUUM FULLが本当に必要となるところまで肥大化することです。 自動バキュームデーモンを使用することにより、この問題は緩和されます。 なぜなら、このデーモンは更新作業に反応して動的にバキューム作業を計画するからです。 完全に作業量を予測することができない限り、デーモンを完全に無効化するのは勧められません。 取り得る妥協案の1つは、いつになく激しい更新作業にのみ反応するよう、デーモンのパラメータを設定することです。 これにより、抑制可能な範囲を維持しつつ、負荷が標準的な場合に計画化されたVACUUMがまとめて作業を行うことを想定することができます。

自動バキュームを使用しない場合の典型的な方式は、データベース全体のVACUUMを1日1回使用頻度が低い時間帯にスケジュールすることです。 必要に応じて、更新頻度の激しいテーブルのバキューム処理をより頻繁に行うよう追加してください。 (非常に高い頻度でデータの更新を行うインストレーションの中では、分間隔位という頻度で高負荷なテーブルのVACUUMを行うこともあります。) 1つのクラスタで複数のデータベースがある場合、それぞれをバキュームすることを忘れないでください。 vacuumdbプログラムが役に立つかもしれません。

ヒント

大規模な更新や削除作業の結果としてテーブルが不要な行バージョンを大量に含む場合、通常のVACUUMでは満足のゆくものではないかもしれません。 もしそのようなテーブルを所有し、それが占有する余分なディスク空間の回収が必要であれば、VACUUM FULL、またはその代わりにCLUSTERやテーブルを書き換えるALTER TABLE構文の1つを使用しなければなりません。 これらのコマンドはテーブル全体を新しいコピーに書き換え、それに対する新規インデックスを作成します。 これらの選択肢はすべて排他ロックを必要とします。 新しいものが完成するまで、テーブルの旧コピーとインデックスは解放されませんので、元のテーブルと同程度の容量の余計なディスク領域も一時的に使用することに注意してください。

ヒント

テーブルの内容が定期的に完全に削除される場合、DELETEの後にVACUUMを使用するよりも、TRUNCATEを使用する方が良いでしょう。 TRUNCATEはテーブルの全ての内容を即座に削除します。 また、その後に不要となったディスク容量を回収するためにVACUUMVACUUM FULLを行う必要がありません。 不利な点は厳格なMVCC動作が違反となることです。

24.1.3. プランナ用の統計情報の更新

PostgreSQL問い合わせプランナは、優れた問い合わせ計画を作成するのに、テーブルの内容に関する統計情報に依存しています。 この統計情報はANALYZEによって収集されます。 このコマンドはそのものを呼び出す以外にも、VACUUMのオプション処理としても呼び出すことができます。 合理的な精度の統計情報を持つことは重要です。 さもないと非効率的な計画を選択してしまい、データベースの性能を悪化させてしまいます。

自動バキュームデーモンが有効になっている場合は、テーブルの内容が大きく変更されたときはいつでも自動的にANALYZEコマンドを発行します。 しかし、特にテーブルの更新作業が興味のある列の統計情報に影響を与えないことが判っている時、手作業により計画されたANALYZE操作を当てにする方が好ましいと管理者は思うかもしれません。 デーモンは、挿入または更新された行数の関数としてANALYZEを厳密に計画します。 しかし、意味のある統計情報の変更につながるかどうかは判りません。

領域復旧のためのバキューム処理と同様、頻繁な統計情報の更新は、滅多に更新されないテーブルよりも更新の激しいテーブルにとってより有益です。 しかし、頻繁に更新されるテーブルであっても、データの統計的な分布が大きく変更されなければ、統計情報を更新する必要はありません。 単純な鉄則は、テーブル内の列の最小値、最大値にどのくらいの変化があったかを考えることです。 例えば、行の更新時刻を保持するtimestamp列の場合、最大値は行が追加、更新されるにつれて、単純に増加します。 こういった列は、おそらく、例えば、あるWebサイト上のアクセスされたページのURLを保持する列よりも頻繁に統計情報を更新する必要があるでしょう。 このURL列の更新頻度も高いものかもしれませんが、その値の統計的な分布の変更は相対的に見ておそらく低いものです。

特定のテーブルに対してANALYZEを実行することができます。 また、テーブルの特定の列のみに対してさえも実行することができます。 ですので、アプリケーションの要求に応じて、他よりも頻繁に一部の統計情報を更新できるような柔軟性があります。 しかし、実際には、操作が高速であるため、単にデータベース全体を解析することが最善です。 ANALYZEは、すべての行を読むのではなく、テーブルから統計的にランダムな行を抽出して使用します。

ヒント

列単位でのANALYZE実行頻度の調整はあまり実用的とは言えるものではありませんが、ANALYZEで集計される統計情報の詳細レベルの調整を列単位で行うことは価値がある場合があります。 WHERE句でよく使用され、データ分布の規則性がほとんどない列は、他の列よりもより細かいデータの度数分布が必要になるでしょう。 ALTER TABLE SET STATISTICSを参照するか、default_statistics_target設定パラメータでデータベース全体のデフォルトを変更してください。

またデフォルトで、関数の選択性に関して利用可能な制限付きの情報があります。 しかし、関数呼び出しを使用する式インデックスを作成する場合、有用な統計情報が関数に関して収集されます。 これにより式インデックスを使用する問い合わせ計画を大きく改良することができます。

ヒント

自動バキュームデーモンは、有益になる頻度を決定する手段がありませんので、外部テーブルに対してANALYZEコマンドを発行しません。 問い合わせが適切な計画作成のために外部テーブルの統計情報が必要であれば、適当なスケジュールでこれらのテーブルに対して手作業で管理するANALYZEコマンドを実行することを勧めます。

24.1.4. 可視性マップの更新

バキュームは、どのページにすべての有効トランザクション(およびページが再度更新されるまでの将来のトランザクション)で可視であることが分かっているタプルのみが含まれるかを追跡するために、各テーブルの可視性マップの保守を行います。 2つの目的があります。 1つ目はバキューム自身が、整理するものがありませんので、こうしたページを次回飛ばすことができます。

2つ目は、PostgreSQLが、背後にあるテーブルを参照することなく、インデックスのみを使用して一部の問い合わせに応えることができるようになります。 PostgreSQLのインデックスにはタプルの可視性に関する情報を持ちませんので、通常のインデックススキャンは合致したインデックス項目のヒープタプルを取り込み、現在のトランザクションから可視であるべきかどうか検査します。 一方でインデックスオンリースキャンはまず可視性マップを検査します。 そのページのタプルがすべて可視であることが分かれば、ヒープの取り出しを省くことができます。 可視性マップによりディスクアクセスを防ぐことができる大規模なデータ群に対して、特に有効です。 可視性マップはヒープより非常に小さいため、ヒープが非常に大きい場合であっても簡単にキャッシュすることができます。

24.1.5. トランザクションIDの周回エラーの防止

PostgreSQLMVCCトランザクションのセマンティクスは、トランザクションID(XID)番号の比較が可能であることに依存しています。 現在のトランザクションのXIDよりも新しい挿入時のXIDを持ったバージョンの行は、未来のものであり、現在のトランザクションから可視であってはなりません。 しかし、トランザクションIDのサイズには制限(32ビット)があり、長時間(40億トランザクション)稼働しているクラスタはトランザクションの周回を経験します。 XIDのカウンタが一周して0に戻り、そして、突然に、過去になされたトランザクションが将来のものと見えるように、つまり、その出力が不可視になります。 端的に言うと、破滅的なデータの損失です。 (実際はデータは保持されていますが、それを入手することができなければ、慰めにならないでしょう。) これを防ぐためには、すべてのデータベースにあるすべてのテーブルを少なくとも20億トランザクションごとにバキュームする必要があります。

定期的なバキューム処理によりこの問題が解決する理由は、VACUUMが行に凍結状態という印をつけて、挿入トランザクションの効果が確実に可視になるような十分遠い過去にコミットされたトランザクションによりそれらが挿入されたことを表すからです。 PostgreSQLは特別なXID、FrozenTransactionIdを確保します。 このXIDは通常のXIDの比較規則には従わず、常に全ての通常のXIDよりも古いものとみなされます。 通常のXID(2以上の値)はmodulo-232という数式を使用して比較されます。 これは、全ての通常のXIDでは、20億のより古いXIDと20億のより新しいXIDが存在することを意味します。 言い換えると、通常のXID空間は終わることなく循環されているということです。 そのため、ある特定のXIDであるバージョンの行を作成すると、そのバージョンの行は、以降の20億トランザクションからはどの通常のXIDについて比較しているのかには関係なく、 過去のものと認識されます。 そのバージョンの行が20億トランザクション以上後にも存在していた場合、それは突然に未来のものとして認識されます。 これを防ぐために、凍結された行バージョンは挿入XIDがFrozenTransactionIdであるかのように扱われ、それで、周回問題に関係なく、すべての通常のトランザクションから過去のものとして認識され、また、そのバージョンの行はどれだけ古いものであろうと、削除されるまで有効状態となります。

注記

9.4より前のバージョンのPostgreSQLでは、行の挿入XIDを実際にFrozenTransactionIdで置換することで凍結が実装されており、これは行のxminシステム列として見えていました。 それより新しいバージョンでは単にフラグのビットをセットするだけで、行の元のxminは後の検証での利用に備えて保存します。 しかし、9.4以前のバージョンからpg_upgradeでアップグレードしたデータベースでは、xminFrozenTransactionId (2)に等しい行がまだあるかもしれません。

また、システムカタログにはxminBootstrapTransactionId (1)に等しい行が含まれる場合があり、これはその行がinitdbの最初の段階で挿入されたことを意味します。 FrozenTransactionIdと同様、この特別なXIDはすべての通常のXIDよりも古いものとして扱われます。

vacuum_freeze_min_ageは、その行バージョンが凍結される前に、XID値がどのくらい経過しているのかを制御します。 この設定値を大きくすることで、そうでなければ凍結状態になる行がすぐに再び修正されるのであれば、不必要な作業を避けられるかもしれませんが、この設定値を小さくすることでテーブルを次にバキュームする必要が起こるまで継続できるトランザクション数が増加します。

VACUUM可視性マップを使用して、テーブルのどのページを走査する必要があるかを決定します。 通常は、不要な行バージョンを持っていないページを読み飛ばします。 このとき、そのページに古いXID値の行バージョンがまだある可能性があったとしても読み飛ばします。 したがって、通常のVACUUMでは必ずしもテーブル内のすべての古い行バージョンを凍結するわけではありません。 定期的にVACUUM積極的なバキュームを実行し、そのときは不要な行も凍結されていないXID値やMXID値もないページのみを読み飛ばします。 vacuum_freeze_table_ageVACUUMがいつこれを行うかを制御します。 つまり、最後にそのような走査が行われた後に実行されたトランザクションの数がvacuum_freeze_table_ageからvacuum_freeze_min_ageを引いた数より大きいとき、全可視ではあるが全凍結ではないページも走査されます。 vacuum_freeze_table_ageを0に設定するとVACUUMはすべての走査についてこのより積極的な戦略を使うようになります。

テーブルをバキュームすることなく処理できる最大の時間は、20億トランザクションから最後に積極的なバキュームを実行した時点のvacuum_freeze_min_ageの値を差し引いたものです。 この時間よりも長期間バキュームを行わないと、データ損失が発生するかもしれません。 これを確実に防止するために、自動バキュームがautovacuum_freeze_max_age設定パラメータで指定された時代より古いXIDを持つ、凍結状態でない行を含む可能性がある任意のテーブルに対して呼び出されます。 (これは自動バキュームが無効であっても起こります。)

これは、あるテーブルがバキュームされていなかったとしても、自動バキュームがおよそautovacuum_freeze_max_age - vacuum_freeze_min_ageトランザクション毎に呼び出されることを意味します。 領域確保のために定常的にバキューム処理を行うテーブルでは、これは重要ではありません。 しかし、(挿入のみで更新や削除が行われないテーブルを含む)静的なテーブルでは、領域確保のためのバキューム処理を行う必要がなくなりますので、非常に長期間静的なテーブルでは、強制的な自動バキューム間の間隔を最大まで延ばすことができます。 記載するまでもありませんが、autovacuum_freeze_max_ageを増やすことでもvacuum_freeze_min_ageを減らすことでも、これを行うことができます。

vacuum_freeze_table_ageに対する有効な最大値は0.95 * autovacuum_freeze_max_ageです。 これより値が高いと値は最大値までに制限されます。 autovacuum_freeze_max_ageより高い値は、周回防止用の自動バキュームがその時点でいずれにせよ誘発され、0.95という乗算係数がそれが起こる前に手動によるVACUUM実行の余地を残すため、意味を持ちません。 経験則に従うと、定期的に計画されたVACUUMもしくは通常の削除・更新作業により誘発された自動バキュームがその期間で実行されるように十分な間隔を残しておくように、vacuum_freeze_table_ageautovacuum_freeze_max_ageより多少低い値に設定されるべきです。 これを余りにも近い値に設定すると、たとえ領域を回収するために最近テーブルがバキュームされたとしても、周回防止用の自動バキュームに帰着します。 一方より低い値はより頻繁な積極的バキュームを引き起こします。

autovacuum_freeze_max_age(およびそれに付随するvacuum_freeze_table_age)を増やす唯一の欠点は、データベースクラスタのサブディレクトリpg_xactpg_commit_tsがより大きな容量となることです。 autovacuum_freeze_max_ageの範囲まですべてのトランザクションのコミット状況と(track_commit_timestampが指定されていれば)タイムスタンプを格納しなければならないためです。 コミット状況は1トランザクション当たり2ビット使用しますので、もしautovacuum_freeze_max_ageをその最大許容値である20億に設定している場合、pg_xactはおよそ0.5ギガバイトまで、pg_commit_tsは約20GBまで膨らむものと考えられます。 これがデータベースサイズ全体に対してとるに足らないものであれば、autovacuum_freeze_max_ageを最大許容値に設定することを勧めます。 さもなければ、pg_xactpg_commit_tsの容量として許容できる値に応じてそれらを設定してください。 (デフォルトは2億トランザクションです。換算するとpg_xactはおよそ50MB、pg_commit_tsはおよそ2GBの容量となります。)

vacuum_freeze_min_age を減らすことにも1つ欠点があります。 これによりVACUUMが大して役に立たなくなるかもしれません。 テーブル行がすぐに変更される場合(新しいXIDを獲得することになります)、行バージョンを凍結することは時間の無駄です。 そのため、この設定は、行の変更が起こらなくなるまで凍結されない程度に大きくすべきです。

データベース内のもっとも古い凍結されていないXIDの年代を追跡するために、VACUUMはシステムテーブルpg_classpg_databaseにXID統計情報を保持します。 特に、テーブルに対応するpg_class行のrelfrozenxid列には、テーブルに対する最後の積極的なVACUUMで使用された凍結切捨てXIDが含まれます。 この切り捨てXIDよりも古いXIDを持つトランザクションにより挿入されたすべての行は凍結状態であることが保証されています。 同様に、データベースに対応するpg_database行のdatfrozenxid列は、データベース内で現れる凍結されていないXIDの下限値です。 これは、そのデータベース内のテーブル当たりのrelfrozenxid値の最小値です。 この情報を検査する簡便な方法は、以下の問い合わせを実行することです。

SELECT c.oid::regclass as table_name,
       greatest(age(c.relfrozenxid),age(t.relfrozenxid)) as age
FROM pg_class c
LEFT JOIN pg_class t ON c.reltoastrelid = t.oid
WHERE c.relkind IN ('r', 'm');

SELECT datname, age(datfrozenxid) FROM pg_database;

age列は切り捨てXIDから現在のトランザクションXIDまでのトランザクション数を測ります。

VACUUMは通常は最後のバキュームの後で変更されたページのみ走査しますが、relfrozenxidはテーブルの凍結されていないXIDを含むかもしれないすべてのページを走査したときのみ繰り上がります。 これは、relfrozenxidvacuum_freeze_table_ageトランザクション年齢より大きい時、VACUUMFREEZEオプションが使用された時、もしくは使用されない行バージョンを削除するため全てのページをバキュームしなければならなくなった時に発生します。 VACUUMがテーブルの全凍結になっていないすべてのページを走査したとき、age(relfrozenxid)は、使用されたvacuum_freeze_min_age設定より若干大きくなるはずです (VACUUMを起動してから始まったトランザクションの数分大きくなります)。 relfrozenxidを繰り上げるVACUUMautovacuum_freeze_max_ageに達するまでにテーブルに対して発行されない場合、そのテーブルに対して自動バキュームが早急に強制されます。

何らかの理由により自動バキュームがテーブルの古いXIDの整理に失敗した場合、システムはデータベースの最古のXIDが周回ポイントから1000万トランザクションに達した場合と似たような警告メッセージを発行し始めます。

WARNING:  database "mydb" must be vacuumed within 177009986 transactions
HINT:  To avoid a database shutdown, execute a database-wide VACUUM in "mydb".

(ヒントで示唆されたように手動VACUUMはこの問題を解決します。 しかし、VACUUMはスーパーユーザで実行されなければなりません。 さもないとシステムカタログの処理に失敗し、このためデータベースのdatfrozenxidを桁上げすることができません。) こうした警告も無視し続け、周回するまでのトランザクションが100万より少なくなると、システムは停止し、新しいトランザクションの起動を拒絶します。

ERROR:  database is not accepting commands to avoid wraparound data loss in database "mydb"
HINT:  Stop the postmaster and vacuum that database in single-user mode.

この100万トランザクションという安全マージンは、管理者が必要なVACUUMコマンドを手作業で実行することで、データを失うことなくリカバリすることができるようにするために存在します。 しかし、システムがこの安全のための停止モードになると、コマンドを実行しませんので、実行するためには、サーバを停止し、シングルユーザモードでサーバを起動してVACUUMを行う他ありません。 この停止モードはシングルユーザモードでは強制されません。 シングルユーザモードの使用に関する詳細はpostgresマニュアルページを参照してください。

24.1.5.1. マルチトランザクションと周回

マルチトランザクションIDは複数のトランザクションによる行ロックをサポートするのに使われます。 タプルヘッダにはロック情報を格納するために限られた容量しかありませんので、二つ以上のトランザクションが同時に行をロックする時には必ず、その情報はマルチプル(訳注:複数の)トランザクションID、略してマルチトランザクションID、にエンコードされます。 あるマルチトランザクションIDにどのトランザクションIDが含まれているかという情報はpg_multixactサブディレクトリに別に格納されており、マルチトランザクションIDのみがタプルヘッダのxmaxフィールドに現れます。 トランザクションIDと同様に、マルチトランザクションIDは32ビットカウンタと対応する記憶領域として実装されており、どちらも注意深い年代管理や記憶領域の整理、周回の取り扱いが必要です。 各マルチトランザクションにはメンバの一覧を保持する独立した記憶領域があり、そこでも32ビットカウンタを使っているので同じように管理しなければなりません。

テーブルの何らかの部分に対しVACUUM走査されるときはいつでも、そのときに見つかったvacuum_multixact_freeze_min_ageよりも古いマルチトランザクションIDはすべて異なる値で置き換えられます。 異なる値とは、0かもしれませんし、単一のトランザクションIDかもしれませんし、より新しいマルチトランザクションIDかもしれません。 各テーブルでは、pg_class.relminmxidがそのテーブルのタプルにまだ現れるマルチトランザクションIDのうちできるだけ古いものを保持しています。 この値がvacuum_multixact_freeze_table_ageよりも古ければ、積極的バキュームが強制されます。 前節で説明したように、積極的なバキュームでは全凍結であるとわかっているページのみがスキップされます。 pg_class.relminmxidに対してその年代を調べるのにmxid_age()を使えます。

積極的なVACUUM走査は、その原因が何かに関わらず、そのテーブルのその値を進めることができます。 結局、データベースすべてのテーブルすべてが走査され、最も古いマルチトランザクション値が進められますので、ディスク上でより古いマルチトランザクションを保持している領域は削除できます。

安全装置として、autovacuum_multixact_freeze_max_ageよりもそのマルチトランザクション年代が大きいどのテーブルに対しても、積極的なバキューム走査が起こります。 メンバ記憶領域の使用量がアドレス指定可能な記憶領域の50%を越えた場合にも、積極的なバキューム走査は、マルチトランザクション年代の一番古いものから始めて、すべてのテーブルに対して段階的に起こります。 この種の積極的走査はどちらも、自動バキュームが名目上は無効にされていても発生します。

24.1.6. 自動バキュームデーモン

PostgreSQLには、省略可能ですが強く推奨される自動バキュームという機能があります。 これはVACUUMANALYZEコマンドの実行を自動化することを目的としたものです。 有効にすると、自動バキュームは大量のタプルの挿入、更新、削除があったテーブルを検査します。 この検査は統計情報収集機能を使用します。 したがって、track_countstrueに設定されていないと、自動バキュームを使用することができません。 デフォルトの設定では、自動バキュームは有効で、関連するパラメータも適切に設定されています。

実際のところ自動バキュームデーモンは複数のプロセスから構成されます。 自動バキュームランチャという永続的デーモンプロセスが存在し、自動バキュームワーカプロセスがすべてのデータベースを処理します。 ランチャは、1つのワーカを各データベースに対しautovacuum_naptime秒ごとに開始するよう試みることにより、時間に対して作業を分散化します。 (したがってインストレーションにN個のデータベースがある場合、新規ワーカがautovacuum_naptime/N秒毎に起動されます。) 同時に最大autovacuum_max_workers個のプロセスが実行可能です。 処理対象のデータベースがautovacuum_max_workersより多くある場合、次のデータベースは最初のワーカが終了するとすぐに処理されます。 それぞれのワーカプロセスはデータベース内の各テーブルを検査し、必要に応じてVACUUMまたはANALYZEコマンドを発行します。 log_autovacuum_min_durationも自動バキュームワーカの活動を監視するために設定できます。

短期間にいくつかの大規模なテーブルがすべてバキューム対象として適切な状態になったとすると、すべての自動バキュームワーカはこうしたテーブルに対するバキューム処理に長い期間占領される可能性があります。 これにより、ワーカが利用できるようになるまで、他のテーブルやデータベースに対するバキュームが行われなくなります。 また、単一データベースに対するワーカ数には制限はありませんが、ワーカはすでに他のワーカによって実行された作業を繰り返さないように試みます。 ワーカの実行数はmax_connections制限にもsuperuser_reserved_connections制限にも計上されないことに注意してください。

テーブルのrelfrozenxid値がautovacuum_freeze_max_ageトランザクション年齢よりも古い場合、そのテーブルは常にバキュームされます (これはfreeze max ageがストレージパラメータにより変更されたテーブルに対しても適用されます。以下を参照)。 さもなければ、直前のVACUUMの後に不要となったタプル数がバキューム閾値を超えると、テーブルはバキュームされます。 このバキューム閾値は以下のように定義されます。


バキューム閾値 = バキューム基礎閾値 + バキューム規模係数 * タプル数

ここで、バキューム基礎閾値はautovacuum_vacuum_threshold、バキューム規模係数はautovacuum_vacuum_scale_factor、タプル数はpg_class.reltuplesです。 不要となったタプル数は、統計情報コレクタから取り出されます。 これは、各UPDATEDELETE操作で更新される、ほぼ正確な数です。 (負荷が高いと一部の情報が失われる可能性があることから、これはほぼ正確な数でしかありません。) テーブルのrelfrozenxid値がvacuum_freeze_table_ageトランザクション年齢より大きい場合、古いタプルを凍結して、relfrozenxidを繰り上げるため、積極的なバキュームが実行されます。 そうでなければ最後のバキュームの後に変更されたページのみ走査されます。

解析でも似たような条件が使用されます。 以下で定義される閾値が、前回のANALYZEの後に挿入、更新、削除されたタプル数と比較されます。


解析閾値 = 解析基礎閾値 + 解析規模係数 * タプル数

一時テーブルには自動バキュームでアクセスすることはできません。 したがってセッションのSQLコマンドを用いて適切なバキュームおよび解析操作を行わなければなりません。

デフォルトの閾値と規模係数は、postgresql.confから取られますが、(他の多くの自動バキューム制御パラメータと合わせて)テーブル毎に上書きすることができます。 より詳細な情報は格納パラメータを参照してください。 テーブルのストレージパラメータで設定が変更されると、そのテーブルを処理する時にその値が使用されます。 そうでなければ、全体設定が使われます。 全体設定についての詳細な情報は19.10を参照してください。

複数のワーカプロセスが実行している場合、自動バキュームコスト遅延パラメータ(19.4.4を参照してください)は実行中のワーカ全体に振り分けられます。 このため、ワーカの実稼働数に関らず、システムに与えるI/Oの総影響は変わりありません。 しかし、テーブル毎のautovacuum_vacuum_cost_delayまたはautovacuum_vacuum_cost_limitストレージパラメータが設定されたテーブルを処理するワーカは振り分けアルゴリズムでは考慮されません。