web-dev-qa-db-ja.com

VACUUMがディスクスペースをオペレーティングシステムに返す

VACUUMは、特別な場合を除いて、通常はオペレーティングシステムにディスク領域を返しません。
ドキュメントから:

VACUUMの標準形式は、テーブルとインデックスの不要な行のバージョンを削除し、将来の再利用に利用できるスペースをマークします。ただし、テーブルの最後にある1つ以上のページが完全に解放されて、排他的なテーブルロックを簡単に取得できる特別な場合を除いて、オペレーティングシステムに領域は返されません。対照的に、VACUUM FULLは、デッドスペースのない完全な新しいバージョンのテーブルファイルを書き込むことにより、テーブルをアクティブに圧縮します。これによりテーブルのサイズが最小化されますが、時間がかかる場合があります。また、操作が完了するまで、テーブルの新しいコピー用に追加のディスク容量が必要です。

問題は、one or more pages at the end of a table become entirely freeが達成されたときにこのデータベースがどのように状態を示すことができるかです。これはVACUUM FULLで実行できますが、実装するための十分なスペースがありません。他の可能性はありますか?

OSにスペースを返すには、 VACUUM FULL を使用します。そこにいる間、あなたはVACUUM FULL ANALYZEを実行していると思います。 マニュアルを引用します

FULL

「フル」バキュームを選択します。これにより、より多くのスペースを再利用できますが、時間がかかり、テーブルを排他的にロックします。このメソッドは、テーブルの新しいコピーを書き込み、操作が完了するまで古いコピーを解放しないため、追加のディスク容量も必要です。通常、これは、テーブル内から大量のスペースを回収する必要がある場合にのみ使用してください。

大胆な強調鉱山。

CLUSTER も、付随的な効果としてそれを実現します。

単純なVACUUMは通常、目的を達成しません( "テーブルの最後にある1つ以上のページが完全に空いている")。それは行を再配列せず、機会が生じたときに、マニュアルの指示からの引用のように、空のページをファイルの物理的な最後からプルーニングするだけです。

行のバッチをINSERTして、他のタプルが追加される前にそれらをDELETEすると、物理ファイルの最後で空のページを取得できます。または、十分な行が削除された場合、偶然に発生する可能性があります。

VACUUM FULLがスペースを再利用できないようにする特別な設定もあります。見る:

テスト用にテーブルの最後に空のページを準備する

システム列ctidは、行の物理的な位置を表します。その列を理解する必要があります。

これで作業し、最後のページからすべての行を削除してテーブルを準備できます。

DELETE FROM tbl t
USING (
   SELECT (split_part(ctid::text, ',', 1) || ',0)')::tid     AS min_tid
        , (split_part(ctid::text, ',', 1) || ',65535)')::tid AS max_tid
   FROM   tbl
   ORDER  BY ctid DESC
   LIMIT  1
   ) d
WHERE t.ctid BETWEEN d.min_tid AND d.max_tid;

今、最後のページは空です。これは同時書き込みを無視します。あなたがそのテーブルに書き込む唯一の人であるか、干渉を避けるために書き込みロックをとる必要があります。

クエリは、条件を満たす行をすばやく特定できるように最適化されています。 tidの2番目の数値は、符号なしint2として保存されたタプルインデックスであり、65535はその型の最大値(2^16 - 1)であるため、安全な上限です。

SQL Fiddle (別のケースの単純なテーブルを再利用します。)

行/表のサイズを測定するツール:

ディスクがいっぱいです

これらの操作のいずれかを行うには、ディスクに小刻みに余裕が必要です。 pg_repack/CLUSTERの代わりとして、コミュニティツール VACUUM FULL もあります。排他ロックを回避しますが、同様に使用するには空き領域が必要です。 マニュアル:

ターゲットテーブルとインデックスの2倍の空きディスク容量が必要です。

最後の手段として、ダンプ/復元サイクルを実行できます。これにより、テーブルとインデックスからすべての膨張が削除されます。密接に関連する質問:

向こうの答えはかなり過激です。状況がそれを許容する場合(外部キーや他の参照が行の削除を妨げない)、およびテーブルへの同時アクセスがない場合、次のことができます。

リモートコンピュータから接続しているディスクにテーブルをダンプします十分なディスクスペース-a for --data-only):

リモートシェルから、テーブルデータをダンプします。

pg_dump -h <Host_name> -p <port> -t mytbl -a mydb > db_mytbl.sql

Pgセッションでは、TRUNCATEテーブル:

-- drop all indexes and constraints here for best performance
TRUNCATE mytbl;

リモートシェルから、同じテーブルに復元します。

psql -h <Host_name> -p <port> mydb -f db_mytbl.sql
-- recreate all indexes and constraints here

これで、死んだ行や膨らみがなくなりました。

しかし、多分それをもっと簡単にすることができますか?

  • 関連のないファイルを削除(移動)して、ディスクに十分なスペースを確保できますか?

  • 最初に小さいテーブルを1つずつVACUUM FULLして、十分なディスク領域を解放できますか?

  • REINDEX TABLE またはREINDEX INDEXを実行して、肥大化したインデックスからディスク領域を解放できますか?

あなたが何をしても、発疹にならないでください。疑問がある場合は、最初にすべてを安全な場所にバックアップしてください。

33