定常的なバキューム作業PostgreSQLデータベースはvacuum作業として知られている定期的な保守を必要とします。多くのインストレーションでは、項23.1.5で説明されているautovacuumデーモンでのvacuum作業を行わせることで充分です。それぞれの状況に合った最善の結果を得るため、そこに書かれているautovacuum作業パラメータの調整が必要かもしれません。データベース管理者によっては、cronもしくはタスクスケジューラスクリプトに従って典型的に実行される、手作業管理のVACUUMコマンドによりデーモンの活動を補足したり、交換したりすることを意図するかもしれません。手作業管理のvacuum作業を適切に設定するためには、以下のいくつかの小区分で説明している問題点を理解することが必須です。autovacuum作業に信頼をおいている管理者にとっても、この資料に目を通すことはそれらの理解とautovacuum作業の調整に役に立つことでしょう。バキューム作業の基本PostgreSQLのVACUUMコマンドは以下の理由により定期的にそれぞれのテーブルを処理しなければなりません。更新、あるいは削除された行によって占められたディスク領域の復旧または再利用。PostgreSQL問い合わせプランナによって使用されるデータ統計情報の更新。トランザクションIDの周回による非常に古いデータの損失を防止。次の小区分で説明されているように、変化する頻度と領域に対するVACUUM操作実行について、これら理由の1つ1つを指示しています。FULLの2つのVACUUMの種類があります。FULLはディスク容量をあけるための再構成が可能ですが、実行にとても時間がかかります。VACUUMの標準形式では、実運用データベースに対する操作と並行して実行させることができます。(SELECT、INSERT、UPDATE、DELETEなどのコマンドは通常通りに動作し続けます。COLUMNなどのコマンドを使用してテーブル定義を変更することはできません。FULLはそれが作用する全てのテーブルに対し排他ロックを必要とするので、それらテーブルのその他の用途と並行して行うことはできません。FULLの不都合としては、テーブルサイズを減少させる一方、それに比例してインデックスサイズを縮小させるわけではないことです。実際、インデックスが増大する場合があります。FULLの使用を避けるべきです。VACUUMには、かなりの量のI/Oトラフィックを発生させます。このため、他の実行中のセッションの性能を劣化させる場合があります。バックグラウンドで実行されるバキューム処理による性能への影響を軽減させることを調整できるような設定パラメータがあります。項18.4.3を参照してください。ディスク容量の復旧PostgreSQLは、行のUPDATEもしくはDELETEが古い行を即座に削除しません。この方法は、多版同時性制御(第13章を参照してください)の恩恵を受けるために必要なものです。あるバージョンの行は他のトランザクションから参照される可能性がある場合は削除されてはなりません。結局は、更新される前の行や削除された行を参照するトランザクションはなくなります。必要なディスク容量が無限大にならないように、これらが占める領域は、新しい行で再利用できるように回収されなければなりません。これはVACUUMを実行することで行われます。VACUUMの標準形式はテーブルとインデックス内の終わっている行バージョンを削除し、将来の再利用を可能にするための場所に印を付けます。テーブルの最後の1つ以上複数ページが完全にすいていて、また排他テーブルロックが容易に獲得できる特殊な場合を除き、その場所をオペレーティングシステムに返還しません。FULLは積極的に行バージョンを以前のページに移動させることでテーブルを圧縮します。このようにしてテーブルの終わりのページを完全に空にさせ、直ぐにそれらをオペレーティングシステムに返還します。多くの行を移動しなければなならい場合、長時間かかります。行の移動には過渡的にそれに対する重複したインデックス項目を作成するので(その新規場所を示す項目は旧項目が削除される前に作成されなければなりません)、このようにして大量の行を移動すると深刻なインデックス膨張の原因になります。FULLの必要性を避けるに充分な頻度で標準VACUUMを行うことです。autovacuumデーモンはこのようにして作動を試みます。FULLを行いません。この手法において、その発想はテーブルを最小サイズに保つのではなく、ディスク空間使用の安定状態を保持することです。それぞれのテーブルは、その最小サイズにバキューム作業とバキューム作業の間で使用されることになる容量を加えたのに等しい空間を占有します。FULLはテーブルをその最小サイズまで縮小し、ディスク空間をオペレーティングシステムに返還するとは言っても、将来そのテーブルが再び肥大するのであれば、これは核心を突いていません。FULLを実行するより大量の更新テーブルを保守するにはより良い取り組みとなります。負荷が少ない夜間に全ての作業を行うように、管理者の何人かは自身で計画したバキューム作業の方を選びます。FULLが本当に必要となるところまで肥大化します。autovacuumデーモンの使用により、この問題を緩和します。デーモンは更新作業に反応して動的にバキューム作業を計画化するからです。予測可能な作業量を保有している以外、デーモンを完全に無効化するのは賢いことではありません。1つの可能性のある妥協案は、いつになく激しい更新作業にのみ反応するよう、デーモンのパラメータを設定することです。すると、負荷が標準的な場合、大量の作業を計画化されたVACUUMが行うことを期待する一方、物事が手が届かなくならないように保つことができます。自動バキュームを使用しない場合の典型的な方式は、データベース全体のVACUUMを1日1回使用頻度が低い時間帯にスケジュールすることです。(非常に高い頻度でデータの更新を行うインストレーションの中では、分間隔位という頻度で高負荷なテーブルのVACUUMを行うこともあります)。1つのクラスタで複数のデータベースがある場合、それぞれをバキュームすることを忘れないでください。vacuumdbプログラムが役に立つかもしれません。大規模な更新や削除作業の結果としてテーブルが大量の意味のない行バージョンを含む場合、どのような形式のVACUUMも完全に満足のゆくものではありません。TABLEを使用します。これらのコマンドはテーブルの全体の新規コピーを書き換え、それに対する新規インデックスを作成します。FULLのように、それらは排他ロックを必要とします。新しいものが完成するまで、テーブルの旧コピーとインデックスは開放されないので、追加ディスク空間も一時的に使用することに注意してください。FULLがたった一つの有効な選択肢です。テーブルの内容が定期的に完全に削除される場合、DELETEの後にVACUUMを使用するよりも、TRUNCATEを使用する方が良いでしょう。TRUNCATEはテーブルの全ての内容を即座に削除します。FULLを行う必要がありません。不利な点は厳格なMVCC動作が違反となることです。プランナ用の統計情報の更新PostgreSQL問い合わせプランナは、優れた問い合わせ計画を作成するのに、テーブルの内容に関する統計情報に依存しています。この統計情報はANALYZEによって収集されます。このコマンドはそのものを呼び出す以外にも、VACUUMのオプション処理としても呼び出すことができます。合理的な精度の統計情報を持つことは重要です。ないと非効率的な計画を選択してしまい、データベース性能を悪化させてしまいます。自動バキュームデーモンが有効になっている場合は、テーブルの内容が正確に変更されたときはいつでも自動的にANALYZEコマンドを発行します。テーブルの更新作業が"興味のある"列の統計情報に影響を与えないことが判っている時、手作業により計画されたANALYZE操作を当てにする方が好ましいと管理者は思うかもしれません。デーモンは、挿入または更新された行数の関数としてANALYZEをきっちりと計画します。意味のある統計情報の変更につながるかどうかは判りません。領域復旧のためのバキューム処理と同様、頻繁な統計情報の更新は、滅多に更新されないテーブルよりも更新の激しいテーブルにとってより有益です。頻繁に更新されるテーブルであっても、データの統計的な分布が大きく変更されなければ、統計情報を更新する必要はありません。単純な鉄則は、テーブル内の列の最小値、最大値にどのくらいの変化があったかを考えることです。行の更新時刻を保持するtimestamp列の場合、最大値は行が追加、更新されるにつれて、単純に増加します。いった列は、おそらく、例えば、あるWebサイト上のアクセスされたページのURLを保持する列よりも頻繁に統計情報を更新する必要があるでしょう。このURL列の更新頻度も高いものかもしれませんが、その値の統計的な分布の変更は相対的に見ておそらく低いものです。特定のテーブルに対してANALYZEを実行することができます。テーブルの特定の列のみに対してさえも実行することができます。アプリケーションの要求に応じて、他よりも頻繁に一部の統計情報を更新できるような柔軟性があります。実際には、操作が高速であるため、単にデータベース全体を解析することが最善です。ANALYZEは、すべての行を読むのではなく、テーブルからランダムに行を抽出して統計処理に使用します。列単位でのANALYZE実行頻度の調整は非常に実用的とは言えるものではありませんが、ANALYZEで集計される統計情報の詳細レベルの調整を列単位で行うことは価値がある場合があります。WHERE句でよく使用され、データ分布の規則性がほとんどない列は、他の列よりもより細かいデータの度数分布が必要になるでしょう。STATISTICSを参照するか、default_statistics_target設定パラメータでデータベース全体のデフォルトを変更してください。トランザクションIDの周回エラーの防止PostgreSQLのMVCCトランザクションのセマンティックは、トランザクションID(XID)番号の比較が可能であることに依存しています。現在のトランザクションのXIDよりも新しい挿入時のXIDを持ったバージョンの行は、"未来のもの"であり、現在のトランザクションから可視であってはなりません。トランザクションIDのサイズには制限(執筆時点では32ビット)があり、長時間(40億トランザクション)稼働しているクラスタはトランザクションの周回を経験します。XIDのカウンタが一周して0に戻り、そして、突然に、過去になされたトランザクションが将来のものと見えるように、つまり、その出力が不可視になります。(実際はデータは保持されていますが、それを入手することができなければ、慰めにならないでしょう)。これを防ぐためには、すべてのデータベースにあるすべてのテーブルを少なくとも20億トランザクションごとにバキュームする必要があります。定期的なバキューム処理によりこの問題が解決する理由は、PostgreSQLが特別なXID、FrozenXIDを区別しているためです。このXIDは常に全ての通常のXIDよりも古いものとみなされます。通常のXID(2以上の値)はmodulo-231という数式を使用して比較されます。これは、全ての通常のXIDでは、20億の"より古い"XIDと20億の"より新しい"XIDが存在することを意味します。言い換えると、通常のXID空間は終わることなく循環されているということです。"過去のもの"と認識されます。そのバージョンの行が20億トランザクション以上後にも存在していた場合、それは突然に未来のものとして認識されます。このデータ損失を防ぐために、20億トランザクションより古いとみなされるより、少し前に古いバージョンの行のXIDをFrozenXIDに再割り当てする必要があります。この特殊なXIDに割り当てられた後は、周回問題に関係なく、全ての通常のトランザクションから"過去のもの"として認識され、また、そのバージョンの行はどれだけ古いものであろうと、削除されるまで好ましい状態となります。この古いXIDの再割り当てはVACUUMで扱われます。vacuum_freeze_min_ageは、XID値がFrozenXIDで置換される前に、旧XID値がどのくらい経過しているのかを制御します。大きなvacuum_freeze_min_ageによりトランザクション情報が長期間保持されます。一方で、この値を小さくすることで、テーブルを次にバキュームする必要が起こるまで継続できるトランザクション数を増加させることができます。VACUUMは通常もはや使用されない行バージョンを持っていないページを読み飛ばしますが、それらのページは旧XID値の行バージョンを未だ所有している可能性があります。全ての旧XIDがFrozenXIDにより置き換えられたかどうかの確証を得るためには、全てのテーブルの走査が必要です。vacuum_freeze_table_ageはVACUUMがバキュームを行った際調整します。テーブル全体にわたる清掃はvacuum_freeze_table_ageからvacuum_freeze_min_ageを差し引いたトランザクションに対しテーブルが完全に走査されていない場合に強制されます。0に設定することでVACUUMが可視性マップを効果的に無視し、常に全てのページを走査するようにさせます。テーブルをバキュームすることなく処理できる最大の時間は、20億トランザクションからVACUUMが前回テーブル全体を走査した際に使用されたvacuum_freeze_min_ageを差し引いたものです。この時間よりも長期間バキュームを行わないと、データ損失が発生します。これを確実に防止するために、自動バキュームデーモンがautovacuum_freeze_max_age設定パラメータで指定された時代より古いXIDを持つ可能性がある任意のテーブルに対して呼び出されます。(これは自動バキュームが無効であっても起こります。vacuum_freeze_min_ageトランザクション毎に呼び出されることを意味します。領域確保のために定常的にバキューム処理を行うテーブルでは、これは重要ではありません。(挿入のみで更新や削除が行われないテーブルを含む)静的なテーブルでは、領域確保のためのバキューム処理を行う必要がなくなりますので、非常に長期間静的なテーブルでは、強制的な自動バキューム間の間隔を最大まで延ばすことができます。記載するまでもありませんが、autovacuum_freeze_max_ageを増やすことでもvacuum_freeze_min_ageを減らすことでも、これを行うことができます。autovacuum_freeze_max_ageです。これより値が高いと値は最大値までに制限されます。autovacuum_freeze_max_ageより高い値は、対包括自動バキュームがその時点でどっちみち誘発され、0.95乗算係数がそれが起こる前に手動によるVACUUM実行の余地を残すため、意味を持ちません。経験から得た方法に従うと、定期的に計画されたVACUUMもしくは通常の削除・更新作業により誘発された自動バキュームがその期間で実行されるように十分な隙間を残しておくように、vacuum_freeze_table_ageはautovacuum_freeze_max_ageより多少低い値に設定されるべきです。これを余りにも近づいた値に設定すると、たとえ余白空間を確保するため最近テーブルがバキュームされたとしても対包括自動バキュームに帰着します。低い値はより頻繁なテーブル全体の走査を引き起こします。autovacuum_freeze_max_age(およびそれに付随するautovacuum_freeze_max_age)を増やす唯一欠点は、データベースクラスタのサブディレクトリpg_clogがより大きな容量となることです。autovacuum_freeze_max_ageの範囲まですべてのトランザクションのコミット状況を格納しなければならないためです。コミット状況は1トランザクション当たり2ビット使用しますので、もしautovacuum_freeze_max_ageがその最大許容値である2億よりすこし少ない値に設定している場合、pg_clogはおよそ0.5ギガバイトまで膨らむものと考えられます。これがデータベースサイズ全体に対してとるに足らないものであれば、autovacuum_freeze_max_ageを最大許容値に設定することを勧めます。なければ、pg_clogの容量として許容できる値に応じてそれらを設定してください。(デフォルトは2000万トランザクションです。換算するとpg_clogはおよそ50メガバイトの容量となります。減らすことにも1つ欠点があります。これによりVACUUMが大して役に立たなくなるかもしれません。テーブル行がすぐに変更される場合(新しいXIDを獲得することになります)、テーブル行のXIDをFrozenXIDに変更することは時間の無駄です。そのため、この設定は、行の変更が起こらなくなるまで凍結されない程度に大きくすべきです。この設定を減らすことによる他の欠点として、行を挿入または変更したトランザクションに関する情報がすぐに失われることです。この情報は、特に、データベース障害の後、何がうまくいかなかったのかを解析する場合、便利になることがあります。この2つの理由により、この設定を減らすことは完全に静的なテーブルでない限りお勧めしません。データベース内のもっとも古いXIDの年代を追跡するために、VACUUMはシステムテーブルpg_classとpg_databaseにXID統計情報を保持します。テーブルpg_class行のrelfrozenxid列には、テーブルに対する最後のテーブル全体のVACUUMで使用された凍結切捨てXIDが含まれます。この切り捨てXIDよりも古い、全ての通常のXIDはそのテーブルのFrozenXIDによって置換されていることが保証されています。同様に、データベースのpg_database行のdatfrozenxid列は、データベース内で現れる通常のXIDの下限値です。これは、そのデータベース内のテーブル当たりのrelfrozenxid値の最小値です。この情報を検査する簡便な方法は、以下の問い合わせを実行することです。pg_database;age列は切り捨てXIDから現在のトランザクションXIDまでのトランザクション数を測ります。VACUUMは通常最後のバキュームから変更されたページのみ走査しますが、relfrozenxidはテーブル全体が走査されたときのみ繰り上がります。FREEZEコマンドが使用された時、もしくは使用されない行バージョンを削除するため全てのページをバキュームしなければならなくなった時、relfrozenxidがvacuum_freeze_table_ageトランザクション年齢より大きい場合走査されます。VACUUMがテーブル全体を走査した直後、age(relfrozenxid)は、使用されたvacuum_freeze_min_age設定より若干大きくなるはずです(VACUUMを起動してから始まったトランザクションの数分大きくなります)。テーブル全体走査VACUUMがautovacuum_freeze_max_ageに達するまでにテーブルに対して発行されない場合、そのテーブルに対してautovacuumが早急に強制されます。何らかの理由により自動バキュームがテーブルの古いXIDの整理に失敗した場合、システムはデータベースの最古のXIDが周回ポイントから1000万トランザクションに達した場合と似たような警告メッセージを発行し始めます。"mydb".(ヒントで示唆されたように手動VACUUMはこの問題を解決します。VACUUMはスーパユーザで実行されなければならず、さもないとシステムカタログの処理に失敗し、従ってデータベースのdatfrozenxidを桁上げすることができません。した警告も無視し続け、周回するまでのトランザクションが100万より少なくなると、システムは停止し、新しいトランザクションの実行を拒絶します。"mydb".この100万トランザクションという安全マージンは、管理者が必要なVACUUMコマンドを手作業で実行することで、データを失うことなくリカバリすることができるようにするために存在します。実行するためには、サーバを停止し、シングルユーザモードのバックエンドを使用してVACUUMを行う他ありません。停止モードはシングルユーザモードのバックエンドでは強制されません。シングルユーザモードのバックエンドの使用に関する詳細はpostgresマニュアルページを参照してください。自動バキュームデーモンPostgreSQLは省略可能では有りますが、強く推奨される自動バキュームという機能があります。これはVACUUMとANALYZEコマンドの実行を自動化することを目的としたものです。有効にすると、自動バキュームは大量のタプルの挿入、更新、削除があったテーブルを検査します。この検査は統計情報収集機能を使用します。したがって、track_countsがtrueに設定されていないと、自動バキュームを使用することができません。デフォルトの設定では、自動バキュームは有効で、関連するパラメータも適切に設定されています。"自動バキュームデーモン"は実際複数のプロセスから構成されます。自動バキュームランチャという永続的デーモンプロセスが存在し、自動バキュームワーカプロセスがすべてのデータベースを処理します。ランチャは、あるワーカの起動が各データベースに対しautovacuum_naptime秒ごとに開始するよう試みることにより、時間に対して作業を分散化します。ワーカはデータベースごとに、同時に最大autovacuum_max_workersプロセスが実行するように、起動されます。autovacuum_max_workersより多くのデータベースを処理させる場合、次のデータベースは最初のワーカが終了するとすぐに処理されます。それぞれのワーカプロセスはデータベース内の各テーブルを検査し、必要に応じてVACUUMまたはANALYZEコマンドを発行します。autovacuum_max_workersの設定は、任意時点におけるワーカの実行可能個数を制限します。短期間にかなり多くのテーブルがすべてバキューム対象として適切な状態になったとすると、すべての自動バキュームワーカはこうしたテーブルに対するバキューム処理に長い期間占領される可能性があります。これにより、ワーカが利用できるようになるまで、他のテーブルやデータベースに対するバキュームが行われなくなります。単一データベースに対するワーカ数には制限はなく、ワーカはすでに他のワーカによって実行された作業を繰り返さないように試みます。ワーカの実行数はmax_connections制限にもsuperuser_reserved_connections制限にも計上されないことに注意してください。ageがストレージパラメータにより変更されたテーブルに対しても適用されます。なければ、直前のVACUUMの後に不要となったタプル数が"バキューム閾値"を超えると、テーブルはバキュームされます。このバキューム閾値は以下のように定義されます。タプル数ここで、バキューム基礎閾値はautovacuum_vacuum_threshold、バキューム規模係数はautovacuum_vacuum_scale_factor、タプル数はpg_class.reltuplesです。不要となったタプル数は、統計情報コレクタから取り出されます。これは、各UPDATE、DELETE操作で更新される、ほぼ正確な数です。(負荷が高いと一部の情報が失われる可能性があることから、これはほぼ正確な数でしかありません。)テーブルのrelfrozenxid値がvacuum_freeze_table_ageトランザクション年齢より大きい場合、テーブル全体は古いタプルを凍結するため走査され、relfrozenxidを繰り上げます。なければ最後のバキュームの後に変更されたページのみ走査されます。以下で定義される閾値が、直前のANALYZEの後に挿入、更新されたタプル数と比較されます。タプル数デフォルトの閾値と規模係数は、postgresql.confから取られますが、テーブル毎に上書きすることができます。詳細な情報は格納パラメータを参照してください。ストレージパラメータで設定が変更されるとその値が使用されます。なければ、全体設定が使われます。全体設定についての詳細な情報は、項18.9を参照してください。基礎閾値と規模係数の他に、ストレージパラメータでを各テーブルに対して設定することができる更に6つのautovacuumパラメータがあります。最初のパラメータ、pg_autovacuumはfalseに設定することでautovacuumデーモンにこのテーブル全体を対象から外すようにします。この場合autovacuumは、トランザクションIDの周回を防ぐためにバキュームする必要がある時のみ、このテーブルを対象とします。autovacuum_vacuum_cost_limitはコストに基づくVacuum遅延機能に対し、テーブル特定の値を設定するために使用されます。vacuum_freeze_table_ageに対する値を設定するために使用されます。複数のワーカプロセスの実行中、コスト制限は実行中のワーカ全体に"振り分け"られます。このため、ワーカの実稼働数に関らず、システムに与える総影響は変わりありません。定常的なインデックスの。