web-dev-qa-db-ja.com

テーブルを再構築せずに削除後にディスク領域を再利用する方法は?

PostgreSQL 9.0 Windows本番サーバーのスペースが不足しています。

100GBデータベースには、TOASTされたバイナリデータを含む大きなテーブルがあります。一部の行を削除したため、スペースをO/Sに戻す必要があります。

テーブルを完全に書き換えるのに十分なスペースがないため、CLUSTERVACUUM FULL、およびpg_repackをすべて読み取ると、テーブルを書き換える必要があります。私のgoogle-fuはこれまで何かを見つけるには不十分でした。

ある程度のダウンタイムは許容されます(約2時間)。ただし、バックアップ/復元が目的に対して遅すぎるため、ステップの間にデータベースを削除することにも熱心ではありません。

質問:テーブル全体を書き換えずにディスク領域をO/Sに戻すにはどうすればよいですか?

(これは本番サーバーなので、ソリューションは信頼できる/推奨/サポートされている必要があります)。

(追伸:何らかの方法でテーブルを再構築できる場合、使用可能な別のより大きなディスクを使用できます。テーブルスペース?)

4
Brendan Hill

CLUSTER/VACUUM FULL/ pg_repack (すべてが自動的にロックを管理する)以外のものを使用する場合は、テーブルへの同時書き込みがないことを確認する必要があります。テーブルを排他的にロックし、すべてを1つのトランザクションで実行するか、同時変更を回避するためにすべての接続をシャットダウンします。

TABLESPACE

はい、あなたの最後のアイデアはうまくいくかもしれません。他のディスクに新しいテーブルスペースを作成します。

CREATE TABLESPACE ts1 LOCATION '/data/disk2';

次に、新しいテーブルスペースにテーブルの最適化されたコピーを作成します。

CREATE TABLE new_tbl 
TABLESPACE ts1 AS
SELECT * FROM tbl
ORDER BY ....  -- ORDER BY is optional 

コピーはデッドローなしで密にパックされます。

次に、古いディスクを削除し、新しいディスクの名前を変更して、新しいディスクを使い続けることができます。

または、何らかの理由で古いディスクに保持する必要がある場合は、古いテーブルを削除し、新しいテーブルの名前を変更して、デフォルトに戻しますテーブルスペース。このステップはずっと速くなりました:

ALTER TABLE tbl SET TABLESPACE pg_default

ドキュメントごと:

このフォームは、テーブルのテーブルスペースを指定されたテーブルスペースに変更し、テーブルに関連付けられたデータファイルを新しいテーブルスペースに移動します。テーブルのインデックスがあっても移動されません。ただし、追加のSET TABLESPACEコマンドを使用して個別に移動できます。 CREATE TABLESPACEもご覧ください。

どちらの方法でも、すべての依存オブジェクトを(再)作成することを忘れないでください。インデックス、外部キー、ビュー、...

まあ、最初はALTER TABLE tbl SET TABLESPACE ...を使用できますが、テーブルは要求どおりに最適化されず、そのまま移動されます。しかし、pg_repackなどを実行するのに十分な余裕があります。

COPY

完全なバックアップ/復元には時間がかかりすぎる可能性がありますが、問題のテーブルに対してのみ実行できます。

COPY tbl TO '/path/to/other/disk/tbl.pgsql';
TRUNCATE tbl;
COPY tbl FROM '/path/to/other/disk/tbl.pgsql';

これでテーブルがぎゅっと詰まっています。

一時テーブル

If十分なRAMがある場合、RAMの一時テーブルを使用して同様のことを行うことができます。はるかに速くなります。詳細な手順:

5

ご使用の環境に、このテーブルの「実際のデータ(削減後)」のサイズよりも多くのディスク容量がある場合。 pg_reorgを使用して、このテーブルの膨張スペースを減らすことができます。または、londiste3インクリメントを使用してこのテーブルをコピーし、交換にかかる時間を短縮できます。ただし、envにこのテーブルよりも多くのスペースがない場合は、削減できません。

1
digoal.zhou

ヒープページ内のタプルを削除できる場合に、膨らみスペースを減らす別の方法があります。この方法では、追加スペースを減らして膨らみテーブルを減らします。 LIKE exp:

pg93@db-172-16-3-150-> psql
psql (9.3.3)
Type "help" for help.

digoal=# create table t_bloat(id int primary key, info text, crt_time timestamp);
CREATE TABLE
digoal=# insert into t_bloat select generate_series(1,100000),md5(random()::text),clock_timestamp();
INSERT 0 100000
digoal=# delete from t_bloat where id<>100000;
DELETE 99999
digoal=# vacuum t_bloat;
VACUUM
digoal=# vacuum t_bloat;
VACUUM
digoal=# select relpages from pg_class where relname='t_bloat';
 relpages 
----------
      233
(1 row)

digoal=# insert into t_bloat select generate_series(1,100),md5(random()::text),clock_timestamp();
INSERT 0 100
digoal=# select split_part(ctid::text,',',1) from t_bloat group by 1;
 split_part 
------------
 (0
 (232
(2 rows)

digoal=# begin;
BEGIN
digoal=# create temp table t_bloat_tmp(like t_bloat);
CREATE TABLE
digoal=# insert into t_bloat_tmp select * from t_bloat where split_part(ctid::text,',',1)='(232';
INSERT 0 1
digoal=# delete from t_bloat where split_part(ctid::text,',',1)='(232';
DELETE 1
digoal=# insert into t_bloat select * from t_bloat_tmp ;
INSERT 0 1
digoal=# end;
COMMIT
digoal=# vacuum t_bloat;
VACUUM
digoal=# select split_part(ctid::text,',',1) from t_bloat group by 1;
 split_part 
------------
 (0
 (1
(2 rows)

digoal=# select relpages from pg_class where relname='t_bloat';
 relpages 
----------
        2
(1 row)

あなたは注意ロックを握ります、これは単なる考えです。

1
digoal.zhou