VACUUM FULL/ja
VACUUMとVACUUM FULL
VACUUM
コマンドと関連する自動バキュームプロセスはPostgreSQLのMVCCの膨張化を制御する手段です。
VACUUM
には大きく2つの形式があります。通常のVACUUM
とVACUUM FULL
です。
これらの2コマンドは実際には大きく異なるものですので、混乱してはいけません。
VACUUM
はテーブルをスキャンし、新しく挿入または更新されるデータで上書きすることができるように、不要となったタプルに空き領域印を付けます。
この詳細についてはIntroduction to VACUUM, ANALYZE, EXPLAIN, and COUNTとPostgreSQLの文書MVCCを参照してください。
適切に設定されていればautovacuumが代わりに面倒をみますので、最近のPostgreSQLデータベースでは直接VACUUM
コマンドの使用が必要になることはまれであることに注意してください。
VACUUM FULL
はVACUUM
とは異なり、削除されていないタプルデータをファイル内で前方にある解放済みの場所に移動します。
ファイルの終わりに空き領域が作られると、領域が解放されたことをOSが理解し、他の用途に再利用できるようにそのファイルを切り詰めます。
この方法、特にVACUUM FULL
が行う方法により使用中のデータを移動することには何らかの大きな欠点と副作用があります。
必要な領域を解放する方法やテーブルを最適化する方法には他に優れた方法があります(後述)ので、基本的にはVACUUM FULL
を使用してはなりません。
9.0ではVACUUM FULLを変更します。 documentationで説明するように、VACUUM FULLの実装は過去のバージョンでCLUSTERを使用した場合の方式に似たものに変わりました。 このため、ここで説明する古めのVACUUM FULLに対するトレードオフの集合はかなり異なってきます。 インデックスの膨張が原因のデータベースの低速化の可能性はこの変更により減少しましたが、VACUUM FULLのロックと一般的な性能に対するオーバーヘッドがありますので、行うことを避けるべき何かがまだ存在します。
VACUUM FULL
を使用する(しない)タイミング
ネットワーク上の間違ったアドバイスや「優れている」に違いないという仮定に基づき、多くの人は定期的に自身のテーブルに対してVACUUM FULL
を実行しています。
これは一般的に本当に間違った考えであり、自身のデータベースを高速にではなく低速にしています。
VACUUM FULL
はほとんどの行が不要となった、つまり、その膨大な内容のほとんどが削除されているテーブルがある場合のみ必要なものです。
そうであっても、緊急に他の目的のためにディスク容量の空きを確保する、または、そのテーブルが今後そのサイズまで増えることがないと想定する場合でない限り、VACUUM FULL
を使用する意味はありません。
逆効果ですので、テーブルの最適化や定期保守として使用してはいけません。
テーブルに対してVACUUM FULL
を実行する時、その操作の間テーブルはロックされます。
このためそのテーブルに対する作業を行うことはできません。
VACUUM FULL
は通常のVACUUMより非常に低速ですので、そのテーブルはしばらく利用できなくなるかもしれません。
もっと重要な点は、VACUUM FULL
はテーブルを小さくしますが、インデックスは小さくしないことです。
実際にはインデックスのサイズは大きくなる可能性があり、低速化、インデックスの使用時のより多くのディスクI/Oの発生、必要とするメモリ量の増加が起こります。
VACUUM FULL
の後にREINDEX
が必要になるかもしれません。
PostgreSQLの文書notes on VACUUM vs VACUUM FULLを参照してください。
代替品
VACUUM FULL
を使用してはならないのであれば、何を使用すべきでしょうか?
Autovacuum
autovacuumを十分な頻度で積極的に実行しているのであれば、テーブルが不要行が回収されないことが原因で、増大(膨張)することは決してないはずです。 このため、OSに不要な領域を返却する必要性は決してないはずです。
自動バキュームはすべてのPostgreSQLのバージョン劇的に改良されています。 また、これが最新版を実行していることを勧める非常に良い理由です。 例えば、8.4では空き領域マップは自動的に管理されるようになり、もはや必要なくなった調整用パラメータを削除し、テーブル膨張の主な原因を取り除きました。
もし自動バキュームがテーブルとインデックスが膨張しないように十分維持できないのであれば、チューニングを行ってください。 手作業のバキュームとインデックスの再構築で置き換えないでください。 (8.4より前では)空き領域マップの設定を増加させる必要があるかもしれません。 より頻繁に自動バキュームを実行するようにチューニングしてください。 または、自動バキュームに対し特定の更新頻度が多いテーブルを他より積極的にバキュームするように設定してください。 あるいは、この両方を行ってください。
VACUUM
他のテーブルやシステムの他の部分で領域が利用できるようにするためにOSに領域を戻す必要がない限り、VACUUM FULL
ではなくVACUUM
を使用すべきです。
テーブルの多くの部分の書き換えを伴う大きな管理作業や更新作業を実行する場合以外で、手作業でテーブルをVACUUM
しなければならないのであれば、おそらく自動バキュームを十分良く設定していません。
CLUSTER
テーブルを詰め込み、(例えば)積極性が不十分な自動バキュームのために累積したテーブルの膨張を取り除くことで、テーブルを最適化しようとしている場合、または、オペレーティングシステムにテーブル内の不要領域を戻そうとしている場合、通常CLUSTER
が最善の方法です。
これはVACUUM FULL
より大きく高速に行われ、テーブルそのものと同様にインデックスのサイズも減り、最適化されます。
しかし、CLUSTER
を実行している間、テーブル内の使用中のデータすべてを保持するのに十分な空き領域が必要です。
ALTER TABLE .. SET DATA TYPE
CLUSTER
に伴う問題は、それがインデックスにしたがってテーブルの順序を変えることです。
テーブルがまだインデックスの順序に近づいていない場合は、各タプルの検索時に散財するテーブルページの読み取りを何度も行わなければならないため、長時間かかります。
より高速な代替方法は、特定の順序を要求しないテーブル全体の書き換えを要求することです。
PostgreSQLバージョン9.0より以前では、こうした操作を呼び出す直接的な方法を提供しません。
しかし次の回避方法を使用することができます。
任意のテーブル列を対象にALTER TABLE
を用いて同じデータ型にその型を変更してください。
これはテーブルの論理的な変更が伴わないことは明確ですが、サーバはテーブルを書き換える必要があり、その時に不要なタプルを取り除きます。
例えば、an_integer_column
がINTEGER
型とすると
ALTER TABLE your_table ALTER an_integer_column SET DATA TYPE integer;
SELECT ... INTO
SELECT ... INTO
コマンドを使用して膨張したテーブルから新しいテーブルにデータをコピーし、インデックスを再作成し、最終的にはテーブルの名前を変えて古いテーブルを新しいテーブルで置き換えるする方が高速になる場合もあります。
しかしCLUSTER
の代わりにこれを使用する価値はほぼありません。
CLUSTER
はほぼ同じことを自動的に行い、かつ並行してインデックスを再構築できるからです。
CLUSTER
の代わりにSELECT ... INTO
を使用したいと考える主な理由は、テーブルのソートを行いたくない場合です。
TRUNCATE TABLE
(WHERE
句のない)DELETE FROM tablename;
を用いて定期的に完全に消去されるテーブルからVACUUM FULL
を使用して領域を解放しているのであれば、TRUNCATE TABLE
を用いることで、2つの手順をまとめ、かつ、非常に高速に行うことができます。
以下の代わりに
DELETE FROM tablename; VACUUM FULL tablename;
以下を記述してください。
TRUNCATE TABLE tablename;
確実にTRUNCATE TABLE
文書の注記における警告を読んでください。
TRUNCATE TABLE
が目的に適していなければ、代わりにCLUSTER
を付けたDELETE
を使用してください。
外部キー参照の対象となるテーブルに対してDELETE
を使用する場合、参照列にインデックスを付けることを検討してください。
外部キー制約の検査における参照テーブル上でのシーケンシャルスキャンを防止することができ、被参照テーブルのDELETE
が高速になります。
VACUUM FULL
によるインデックス膨張の復旧
定常的にVACUUM FULL
を使用することで膨張してしまったインデックスがある場合、通常 CLUSTER
を使用してテーブルとインデックスを書き換えることが最善です。
長期間テーブルをロック状態とするゆとりがなければ、テーブル上で問い合わせを実行させ続けながら各インデックスを個別に再構築することができます。
残念ながらPostgreSQLにはREINDEX CONCURRENTLY
コマンドはありません。
しかし、CREATE INDEX ... CONCURRENTLY、ALTER INDEX ... RENAMEおよびDROP INDEXを用いて、新しいインデックスの作成、古いインデックスと新しいインデックスの名前を置き換え、古いインデックスを削除することをおおよそ模擬することができます。
プライマリキーなどインデックスの一部は削除することができませんので、これはすべてのインデックスを整理する手法にならないかもしれません。
ではなぜVACUUM FULL
があるのでしょう?
理由のほぼ歴史的なものです。
具体的には、完全にMVCCで安全なCLUSTER
が利用できる用になる前はもっと有用なものでした。
また、自動バキュームが導入され、かつデフォルトで有効になる前では、深刻なテーブル膨張は良く起こりました。
他に優れた代替方法がない、VACUUM FULL
が有用となる使用方法が1つあります。
それはディスクフル状態からの復旧です。
VACUUM FULL
はCLUSTER
よりもテーブルを小さくするために必要とする空き領域がかなり少なく済みます。
このため容量を(ほぼ)完全に使い切った場合でも有用です。
VACUUM FULLはremoval from PostgreSQL 8.5(この後PostgreSQL 9.0に名前が変わりました)のように提案されています。 この記事ではここで示した提言に対していくつか追加サポートを提供しています。 そこで提案された変更は実装されませんでした。 少ないディスク領域からの復旧などの古いVACUUM FULLが有用となる数少ない状況は、古いコードの問題よりも重要だとされていません。 古いコードの問題には、9.0リリースの新しいレプリケーション機能との非互換性が含まれています。
元原稿 --Ringerc 03:48, 26 November 2009 (UTC)