web-dev-qa-db-ja.com

大きなテーブルに新しい列を作成する最良の方法は?

Postgresには2.2 GBのテーブルがあり、7,801,611行が含まれています。ここにuuid/guid列を追加していますが、その列にデータを入力するための最良の方法は何ですか(NOT NULL制約を追加したいため)。

私がPostgresを正しく理解している場合、更新は技術的には削除と挿入なので、これは基本的に2.2 GBテーブル全体を再構築しています。また、スレーブが実行されているので、それが遅れることはありません。

時間をかけてゆっくりと作成するスクリプトを書くよりも良い方法はありますか?

35
Collin Peters

「最良の」回答はありませんが、物事をかなり速く完了する可能性がある「最も悪い」回答があります。

テーブルに2MM行があり、デフォルトで最初に設定されているセカンダリタイムスタンプ列を追加しようとすると、更新パフォーマンスが非常に高くなります。

ALTER TABLE mytable ADD new_timestamp TIMESTAMP ;
UPDATE mytable SET new_timestamp = old_timestamp ;
ALTER TABLE mytable ALTER new_timestamp SET NOT NULL ;

40分間ハングした後、これをどれだけかかるかを知るために、これを少量ずつ試してみました。予測は約8時間でした。

受け入れられた答えは間違いなく優れていますが、このテーブルは私のデータベースで頻繁に使用されています。 FKEYを適用する数十のテーブルがあります。非常に多くのテーブルでFOREIGN KEYSを切り替えないようにしました。そして、ビューがあります。

ドキュメント、ケーススタディ、StackOverflowを少し検索して、「A-Ha!」を取得しました。瞬間。ドレインはコアUPDATEではなく、すべてのINDEX操作にありました。私のテーブルには12個のインデックスがありました。一意の制約用、クエリプランナーの高速化用、フルテキスト検索用のインデックスです。

更新されたすべての行は、DELETE/INSERTだけでなく、各インデックスの変更と制約のチェックのオーバーヘッドも処理していました。

私の解決策は、すべてのインデックスと制約を削除し、テーブルを更新してから、すべてのインデックス/制約を再び追加することでした。

以下を実行するSQLトランザクションを作成するには、約3分かかりました。

  • ベギン;
  • 削除されたインデックス/制約
  • テーブルを更新する
  • インデックス/制約を再度追加する
  • コミット;

スクリプトの実行には7分かかりました。

受け入れられた答えは間違いなくより良く、より適切です...そして実質的にダウンタイムの必要性を排除します。私の場合でも、そのソリューションを使用するにはかなり「開発者」の作業が必要であり、計画的なダウンタイムの30分のウィンドウがあり、それを達成できました。このソリューションでは、10で対処しました。

17