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
を実行して、肥大化したインデックスからディスク領域を解放できますか?
あなたが何をしても、発疹にならないでください。疑問がある場合は、最初にすべてを安全な場所にバックアップしてください。