仮定
Qに情報がないため、次のことを想定します。
- データは、データベースサーバー上のファイルから取得されます。
- データは
COPY
出力と同じようにフォーマットされ、行ごとに一意で id
ターゲットテーブルに一致します。
そうでない場合は、最初に適切にフォーマットするか、COPY
オプションを使用してフォーマットを処理します。
- ターゲット表のすべての単一行またはほとんどの行を更新しています。
- ターゲット表をドロップして再作成する余裕があります。
つまり、同時アクセスはありません。それ以外の場合は、この関連する回答を検討してください。
- インデックスを除いて、依存オブジェクトはまったくありません。
溶液
3番目の箇条書きのリンクで説明されているのと同様のアプローチをお勧めします。主要な最適化あり。
一時テーブルを作成するには、より簡単で高速な方法があります。
CREATE TEMP TABLE tmp_tbl AS SELECT * FROM tbl LIMIT 0;
データベース内のUPDATE
一時テーブルからの単一のビッグは、データベースの外部からの個々の更新よりも数桁高速です。
ではPostgreSQLのMVCCモデル、UPDATE
新しい行バージョンを作成し、削除したとして、古いものをマークするための手段。それは、INSERT
と同じくらい高価DELETE
です。さらに、大量のタプルが残っています。とにかくテーブル全体を更新しているため、新しいテーブルを作成して古いテーブルを削除する方が全体的に高速です。
使用可能な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更新も可能になります。
この密接に関連するSOの回答を使用UPDATE
して、同様の手順を概説しました。