Ubuntu 12.04でのPG 9.1の使用。
現在、データベースで大量のUPDATEステートメントを実行するには、最大24時間かかります。
UPDATE table
SET field1 = constant1, field2 = constant2, ...
WHERE id = constid
(IDで識別されるオブジェクトのフィールドを上書きしているだけです。)値は外部データソースから取得されます(テーブル内のDBにはまだありません)。
テーブルにはそれぞれ少数のインデックスがあり、外部キー制約はありません。最後までCOMMITは行われません。
DB全体のpg_dump
をインポートするには2時間かかります。これは、私たちが合理的に対象とすべきベースラインのようです。
PostgreSQLのデータセットを何らかの方法で再インポートして再インポートするカスタムプログラムを作成する前に、一括更新のパフォーマンスをインポートのパフォーマンスに近づけるためにできることはありますか? (これは、ログ構造のマージツリーがうまく機能すると私たちが信じている領域ですが、PostgreSQL内で私たちにできることがあるかどうか疑問に思っています。)
いくつかのアイデア:
基本的に、試すことはたくさんありますが、最も効果的なものは何か、他のことを見落としているかどうかはわかりません。次の数日間は実験に費やしますが、ここでも質問したいと思いました。
テーブルに同時負荷がありますが、それは読み取り専用です。
Qに情報が不足しているので、次のように想定します。
COPY
出力と同様にフォーマットされ、ターゲットテーブルと一致する行ごとにuniqueid
が付けられます。COPY
オプションを使用してフォーマットを処理します。番目の箇条書きのリンク で概説されているのと同様のアプローチを使用することをお勧めします。主要な最適化。
一時テーブルを作成するには、より簡単で高速な方法があります。
CREATE TEMP TABLE tmp_tbl AS SELECT * FROM tbl LIMIT 0;
一時テーブル内部からの単一の大きなUPDATE
は、データベースの外部からの個別の更新よりも数桁高速です。
PostgreSQLのMVCCモデル では、UPDATE
は新しい行バージョンを作成し、古い行バージョンを削除済みとしてマークすることを意味します。これは、INSERT
とDELETE
を組み合わせた場合と同じくらいの費用がかかります。さらに、それはあなたにたくさんの死んだタプルを残します。とにかくテーブル全体を更新しているので、新しいテーブルを作成して古いテーブルを削除する方が全体的に速くなります。
If十分なRAMが利用できる場合は、 temp_buffers
を設定します(このセッションのみ! )一時テーブルをRAMに保持するのに十分な高さ-他に何かする前。
RAMの必要量を見積もるには、小さなサンプルでテストを実行し、 dbオブジェクトサイズ関数 を使用します。
SELECT pg_size_pretty(pg_relation_size('tmp_tbl')); -- complete size of table
SELECT pg_column_size(t) FROM tmp_tbl t LIMIT 10; -- size of sample rows
SET temp_buffers = '1GB'; -- example value
CREATE TEMP TABLE tmp_tbl AS SELECT * FROM tbl LIMIT 0;
COPY tmp_tbl FROM '/absolute/path/to/file';
CREATE TABLE tbl_new AS
SELECT t.col1, t.col2, u.field1, u.field2
FROM tbl t
JOIN tmp_tbl u USING (id);
-- Create indexes like in original table
ALTER TABLE tbl_new ADD PRIMARY KEY ...;
CREATE INDEX ... ON tbl_new (...);
CREATE INDEX ... ON tbl_new (...);
-- exclusive lock on tbl for a very brief time window!
DROP TABLE tbl;
ALTER TABLE tbl_new RENAME TO tbl;
DROP TABLE tmp_tbl; -- will also be dropped at end of session automatically
テーブル名がOIDすぐに、しかし新しいテーブルに別のOIDがあります。テーブルは一貫性を保ちますが、並行操作は例外を受け取り、繰り返す必要がある場合があります。この関連する回答の詳細:
UPDATE
ルートに移動する必要がある場合は、更新中に不要なインデックスを削除し、後で再作成します。個々の行ごとにインデックスを更新するよりも、1つのピースでインデックスを作成する方がはるかに安価です。 HOTの更新 も可能です。
UPDATE
を使用した同様の手順の概要を この密接に関連するSOの回答 で説明しました。
データを構造化ファイルで利用できるようにする場合は、 foreign data wrapper を使用してデータを読み取り、ターゲットテーブルでマージを実行できます。