巨大なテーブルにシリアル列を追加する最も効率的な方法


10

BIGSERIAL列を巨大なテーブルに追加する最も速い方法は何ですか(〜3 Bil。行、〜174Gb)?

編集:

  • 列を既存の行の増分値にしたい(NOT NULL)。
  • フィルファクターを設定しませんでした(振り返ってみると、これは悪い決定のように見えます)。
  • ディスク容量に問題はありません。できるだけ高速にしてください。

回答:


12

どうしたの:

ALTER TABLE foo ADD column bar bigserial;

一意の値が自動的に入力されます(1から始まります)。

既存のすべての行に数値が必要な場合は、テーブルのすべての行を更新する必要があります。それともしませんか?

データページのデッドタプルまたは空き領域を再利用できない場合、テーブルはサイズの2倍に膨れ上がります。操作のパフォーマンスは、FILLFACTOR100未満の場合、またはテーブル全体にランダムなデッドタプルが広がる場合に多くのメリットがあります。それ以外の場合は、VACUUM FULL ANALYZE後で実行してディスク領域を回復することができます。しかし、これは速くはありません。

pgstattuple
この拡張機能に興味があるかもしれません。テーブルの統計を収集するのに役立ちます。死んだタプルと空き領域について調べるには:

データベースごとに拡張機能を1回インストールします。

CREATE EXTENSION pgstattuple;

コール:

SELECT * FROM pgstattuple('tbl');

オルタナティブ

新しいテーブルを作成する余裕がある場合は、依存するビュー、外部キー、...

古いテーブルの空のコピーを作成します。

CREATE new_tbl AS
SELECT *
FROM   old_tbl
LIMIT  0;

bigserial列を追加します。

ALTER new_tbl ADD column bar bigserial;

古いテーブルからデータを挿入し、bigserialを自動的に入力します。

INSERT INTO new_tbl
SELECT *    --  new column will be filled with default
FROM   old_tbl
ORDER  BY something; -- or don't order if you don't care: faster

INSERTのSELECTに新しいbigserial列がなく、デフォルト値が自動的に入力されます。すべての列を詳しく説明nextval()し、SELECTリストに追加して同じ効果を得ることができます。

すべてのデータが新しいテーブルにあることを確認してください。
インデックス、制約、古いテーブルに持っていた、トリガーの追加になりましたが

DROP TABLE old_tbl;
ALTER TABLE new_tbl RENAME TO old_tbl;

全体的にかなり速いかもしれません。これにより、膨らみのないバニラテーブル(およびインデックス)が残ります。

空き容量として、テーブルの状態に応じて、古いテーブルのサイズに近い空きディスク領域が必要です。ただし、テーブルの肥大化のため、最初の単純なメソッドでも同様に必要になる場合があります。ここでも、詳細はテーブルの状態によって異なります。


3
代替を単一のトランザクションでラップすると、はるかに高速になります。追加fsyncのs を回避します
フランクハイケンズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.