web-dev-qa-db-ja.com

Postgres:生成されるWALファイル/サイズの量を理解する

特定の操作がどのようにしてhuge量のWALファイルを生成するかを常に驚いています。

私はこれらのWALファイルをポイントインタイムリカバリにしたいので(さらに、毎晩フルダンプを実行します)、提供されている基本的な機能はwantedであり、変更したくありません(つまり、WALアーカイブをオフにする方法などは探していません。

これらの設定でPostgres 9.5を使用する:

wal_level = archive
checkpoint_timeout = 20min
max_wal_size = 1GB
min_wal_size = 80MB
archive_command = 'test ! -f /backup/wal/%f && cp %p /backup/wal/%f'

私は今日このステートメントを実行しました:

WITH table2_only_names AS (
    SELECT id , name FROM table2
)
UPDATE table1
SET table2_name = table2_only_names.name
FROM table2_only_names
WHERE table1.table2_id = table2_only_names.id;

表1

CREATE TABLE public.table1 (
  id BIGINT PRIMARY KEY NOT NULL DEFAULT nextval('table1_id_seq'::regclass),
  table2_id BIGINT,
  table3_id BIGINT,
  positive_count INTEGER NOT NULL DEFAULT 0,
  neutral_count INTEGER NOT NULL DEFAULT 0,
  negative_count INTEGER NOT NULL DEFAULT 0,
  is_blocked BOOLEAN NOT NULL DEFAULT false,
  blocker_id BIGINT,
  group BIGINT,
  created TIMESTAMP WITH TIME ZONE,
  modified TIMESTAMP WITH TIME ZONE,
  table4_id BIGINT,
  name CHARACTER VARYING(255)
);
CREATE UNIQUE INDEX idx1 ON table1 USING BTREE (table3_id, table2_id);
CREATE INDEX idx2 ON table1 USING BTREE (table3_id);
CREATE INDEX idx3 ON table1 USING BTREE (table2_id);
CREATE INDEX idx4 ON table1 USING BTREE (group);
CREATE INDEX idx5 ON table1 USING BTREE (blocker_id);
CREATE INDEX idx6 ON table1 USING BTREE (table4_id);

15 Mio行、テーブルサイズ〜3,4GB、インデックスサイズ7GB

表2

CREATE TABLE public.table2 (
  id BIGINT PRIMARY KEY NOT NULL DEFAULT nextval('table2_id_seq'::regclass),
  name CHARACTER VARYING(255),
);

10 Mio行、テーブルサイズ〜2GB、インデックスサイズ3,4GB

実行時間は約55分でした(ここでは不満はありません)。

生成されたWALファイルの量は予想外に膨大でした。前述のWALアーカイブは100 GBの専用パーティション上にあり、クエリが開始した時点では、約30 GBは無料でした。

15〜20分後にディスク領域が<10GBになり、「古い」WALアーカイブを削除し始めたので、十分ではありませんでした。このステートメントによって生成されたWALアーカイブファイルをすでに削除する必要があると確信していた場合、私はこれまで絶えずこれを行わなければなりませんでした。

問題のテーブルは、その間、他のプロセスでは使用されませんでしたが、他のテーブルの「通常の」操作は続行されました。

disk usage graph

クエリを開始した時刻と終了した時刻をマークしました。 WALアーカイブファイルを削除した場所を明確に確認できます。

私には、なぜこれほど多くのものが生成されるのかは謎であり、どれほどの量が必要で、いつ操作がストライクするかが予測できないため、現在は問題となっています。

必要なスペースの量をよりよく理解するために何が欠けていますか?これらは回避できますか?私は何か間違ったことをしていますか?

4
mark

PostgreSQLで行を更​​新すると、通常、更新された列だけでなく行全体のコピーが作成され、古い行が削除済みとしてマークされます。新しいコピーでは、WAL全体をログに記録する必要があります。 full_page_writesがオンになっていて、チェックポイントの間隔が狭すぎる場合は、平均して古い行もWALでログに記録されます。

更新された行のほとんどすべてが、その行のすべてのインデックスも更新する必要があるでしょう。これは、行の新しいバージョンが古いバージョンと同じページに収まらないため、インデックスは新しいバージョンを見つける場所を知っている必要があるためです。

したがって、テーブル全体を2回(古い行で1回、新しい行で1回)、すべての場合はインデックスもログに記録します。また、WALレコードにはかなりのオーバーヘッドがあります。また、full_page_writesをオンにしてチェックポイントを頻繁に行うと、事態はさらに悪化します。

では、音量を下げるためのオプションは何ですか?

1)更新の多くが縮退している(すでに更新されている値に更新されている)場合は、追加のwhere句を使用してそれらの更新を抑制できます。

WITH table2_only_names AS (
    SELECT id , name FROM table2
)
UPDATE table1
SET table2_name = table2_only_names.name
FROM table2_only_names
WHERE table1.table2_id = table2_only_names.id
AND table2_name is distinct from table2_only_names.name;

2)ほとんどのWALファイルは非常に圧縮可能です。次のような圧縮コマンドをarchive_commandに含めることができます

 archive_command = 'set -C -o pipefail; xz -2 -c %p > /backup/wal/%f.xz'

もちろん、recovery_commandを逆に実行する必要があります。

3)9.5を使用しているため、wal_compressionをオンにしてみてください。

4)full_page_writesをオフにしてみることもできますが、ほとんどのストレージハードウェアでは、クラッシュした場合にデータが破損するリスクがあります。または、この操作中にチェックポイントが頻繁に発生する場合は、チェックポイントが頻繁に発生しないようにして、full_page_writesをオンにした場合の影響を少なくすることができます。

5
jjanes