web-dev-qa-db-ja.com

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

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

編集:

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

どうしたの:

_ALTER TABLE foo ADD column bar bigserial;
_

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

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

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

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

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

_CREATE EXTENSION pgstattuple;
_

コール:

_SELECT * FROM pgstattuple('tbl');
_

オルタナティブ

If新しいテーブルを作成する余裕があり、依存するビュー、外部キーなどを壊します...

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

_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;
_

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

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

12