VACUUM FULL/ja

From PostgreSQL wiki
Jump to navigationJump to search

VACUUMとVACUUM FULL

VACUUMコマンドと関連する自動バキュームプロセスはPostgreSQLのMVCCの膨張化を制御する手段です。 VACUUMには大きく2つの形式があります。通常のVACUUMVACUUM FULLです。 これらの2コマンドは実際には大きく異なるものですので、混乱してはいけません。

VACUUMはテーブルをスキャンし、新しく挿入または更新されるデータで上書きすることができるように、不要となったタプルに空き領域印を付けます。 この詳細についてはIntroduction to VACUUM, ANALYZE, EXPLAIN, and COUNTとPostgreSQLの文書MVCCを参照してください。 適切に設定されていればautovacuumが代わりに面倒をみますので、最近のPostgreSQLデータベースでは直接VACUUMコマンドの使用が必要になることはまれであることに注意してください。

VACUUM FULLVACUUMとは異なり、削除されていないタプルデータをファイル内で前方にある解放済みの場所に移動します。 ファイルの終わりに空き領域が作られると、領域が解放されたことを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_columnINTEGER型とすると

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 ... CONCURRENTLYALTER INDEX ... RENAMEおよびDROP INDEXを用いて、新しいインデックスの作成、古いインデックスと新しいインデックスの名前を置き換え、古いインデックスを削除することをおおよそ模擬することができます。 プライマリキーなどインデックスの一部は削除することができませんので、これはすべてのインデックスを整理する手法にならないかもしれません。

ではなぜVACUUM FULLがあるのでしょう?

理由のほぼ歴史的なものです。 具体的には、完全にMVCCで安全なCLUSTERが利用できる用になる前はもっと有用なものでした。 また、自動バキュームが導入され、かつデフォルトで有効になる前では、深刻なテーブル膨張は良く起こりました。

他に優れた代替方法がない、VACUUM FULLが有用となる使用方法が1つあります。 それはディスクフル状態からの復旧です。 VACUUM FULLCLUSTERよりもテーブルを小さくするために必要とする空き領域がかなり少なく済みます。 このため容量を(ほぼ)完全に使い切った場合でも有用です。

VACUUM FULLはremoval from PostgreSQL 8.5(この後PostgreSQL 9.0に名前が変わりました)のように提案されています。 この記事ではここで示した提言に対していくつか追加サポートを提供しています。 そこで提案された変更は実装されませんでした。 少ないディスク領域からの復旧などの古いVACUUM FULLが有用となる数少ない状況は、古いコードの問題よりも重要だとされていません。 古いコードの問題には、9.0リリースの新しいレプリケーション機能との非互換性が含まれています。

元原稿 --Ringerc 03:48, 26 November 2009 (UTC)