Home > pgsql > 勝手に添削「PostgreSQL VACUUM FULLせずに不要領域を削除する」

勝手に添削「PostgreSQL VACUUM FULLせずに不要領域を削除する」

そういう時はdeleteではなくtruncateを使う方法もあります。 truncateはいきなりテーブルを(不要領域を残すことなく)空っぽにするSQLです。

なので、とても大きいテーブルのごく一部のデータだけ残して他を消す手順としては、

  1. 同じテーブルレイアウトの一時保存先となるテーブルを作る
  2. 一時保存先のテーブルにレコードを移行する
  3. 元のテーブルをtruncate
  4. 一時保存先のテーブルからレコードを戻す
  5. 一時保存先テーブルをdrop

この手順であればテーブルのOIDも変わりません。

残すレコードが多ければ、3と4の間で一旦インデックスを削除して、5の後でインデックスを作り直した方がいいかもしれません。あと、一時保存先のテーブルは、CREATE TEMPORARY TABLEを使った方が速い(し、最後にテーブルをdropする手間も省ける)と思います。

なので全体的な操作としては、

CREATE TEMP TABLE items_temp SELECT * FROM items LIMIT 0;
INSERT INTO items_temp SELECT * FROM items WHERE ...;
TRUNCATE items;
INSERT INTO items SELECT * FROM items_temp;

といった感じです。もう一つついでに。

CREATE TABLE items_new AS SELECT * FROM items LIMIT 0;

は、

CREATE TABLE items_new (LIKE items);

と書くこともできます。この"LIKEほげほげ"は、(今回は必要ありませんが)オプションによって制約やデフォルト値もコピーでき、 また以下のように、カラムを追加することもできるので、「似てるけどちょっと違うテーブル」を作る時に便利です。

CREATE TABLE items_new (newcol1 int, LIKE items, newcol2 int);

Writeback:3

from shin1x1 2007/11/02 (Fri) 16:05:31
添削ありがとうございます!
元記事を書いた者です。

質問なのですが、この方法だとtruncate後、insert intoで一時テーブルから書き戻すのに時間がかかりませんか。
後出しになるのですが、今回は削除後に残すレコードだけでも数Gあったので元記事のような対応を行いました。
私が思い違いしているようでしたら教えて頂ければ嬉しいです。:-D

create tableのlike句は知りませんでした。
なるほどこれは便利ですね。勉強になります。;-)
from いしだ 2007/11/02 (Fri) 16:28:47
こんにちは。いつもCakePHPの記事を参考にさせていただいてます。

おっしゃる通り、トータルでかかる時間は私の方法の方が長いです。残すレコードが大量にある場合はこの方法は難しいかもしれませんね。

というわけでもう一つ方法を思いつきました(ちょっとトリッキーですが)、後で書きます。
cluster from L.star 2007/11/06 (Tue) 20:05:09
この場合、わざわざcreate temp tableとinsertを分ける必要は無いかも。

もしインデックスがついているテーブルなら、Clusterコマンドで一発不要領域削除可能なことはあまり知られていませんね。非常に削除領域が多い場合有用なのですが。

ちなみに、

・XIDがらみがありますので、Clusterがあればvacuum不要では無い
・relfilenodeが変わるので、直でファイルをいじる場合は注意。これはtruncateも同じ。
・インデックスが大量にある場合vacuum fullは遅い。8.2へのアップグレードか、インデックスを消してからやってみるといいかも。
・ロックしていいなら、実は一時テーブル使わずにCOPYを一時領域に使うのが最強のような。
Comment Form

writeback message: Ready to post a comment.

TrackBack ping me at
http://www.mono-space.net/blog/pgsql/e071102_delete_vs_truncate.trackback

Page Top