2016-04-18 20 views
0

私は非常に小さなテーブル(約1milの行)を持っており、制約を落として新しいカラムを追加します。以下のクエリは約5分間ハングアップし、ロールバックする必要があります。PostgreSQLの巨大なテーブルにダウンタイムなしでカラムを追加する

BEGIN WORK; 
LOCK TABLE usertable IN SHARE MODE; 
ALTER TABLE usertable ALTER COLUMN email DROP NOT NULL; 
COMMIT WORK; 

別のアプローチは、インターネットで同様の質問に提案 -

CREATE TABLE new_tbl 
(
    field1 int, 
    field2 int, 
    ... 
); 

INSERT INTO new_tbl(field1, field2, ...) 
(
    SELECT FROM ... -- use your new logic here to insert the updated data 
) 

CREATE INDEX -- add your constraints and indexes to new_tbl 

DROP TABLE tbl; 

ALTER TABLE tbl_new RENAME tbl; 
  1. は新しいものに新しいテーブルに古いテーブルから
  2. 挿入レコードを作成します(第2少ないしを取る)
  3. 古いテーブルを削除 - このクエリは約5分〜です。ロールバックしなければならなかった。私のために働かない。古い古いテーブルを削除

から

  • 改名新しい作成されたテーブルは、単純にハングアップします。しかし、私は100万行の新しいテーブルをドロップしようとするとすぐに動作します。なぜ古いテーブルを落とすのに時間がかかりますか?

    SELECT blocked_locks.pid  AS blocked_pid, 
         blocked_activity.usename AS blocked_user, 
         blocking_locks.pid  AS blocking_pid, 
         blocking_activity.usename AS blocking_user, 
         blocked_activity.query AS blocked_statement, 
         blocking_activity.query AS blocking_statement 
        FROM pg_catalog.pg_locks   blocked_locks 
        JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid 
        JOIN pg_catalog.pg_locks   blocking_locks 
         ON blocking_locks.locktype = blocked_locks.locktype 
         AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE 
         AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation 
         AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page 
         AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple 
         AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid 
         AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid 
         AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid 
         AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid 
         AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid 
         AND blocking_locks.pid != blocked_locks.pid 
        JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid 
        WHERE NOT blocked_locks.granted; 
    

    私は、私の操作を待っている多くの並行書き込み/読み出しを見ることができます。私はテーブルをロックしていたので、私は古いテーブルを落とせない理由を本当に考えていません。

    古いテーブルでは真空を実行しても問題ありませんでした。

    なぜ私は古いテーブルを削除できないのですか最近作成されたテーブルを削除するのに比べて時間がかかるのはなぜですか?

  • +1

    'alter table'はテーブルロックを要求しますので、' lock table'を手動で実行する必要はありません。 'drop not null'はメタデータの更新に過ぎず、文が排他ロックを取得してから数ミリ秒かかるだけです。その文が長時間実行されているとわかると、DDLは他のトランザクションを待っています。 2番目のバージョンはそれを変更しません。 'drop table'は同じロックを待たなければなりません。 「アイドル・イン・トランザクション」接続が掛かっていないことを確認しましたか? –

    +0

    DDLは、ある期間、常に排他ロックを必要とします。たぶんスワップ古い<-->新しいテーブルメソッドは、より小さいサービスウィンドウが必要になりますが、依然として排他アクセスが必要です。 – joop

    答えて

    1

    他のテーブルのFKのテーブル元のテーブル原因を削除/名前変更できませんでした。一度私はそれをドロップアウトし、テーブルの名前を変更するアプローチは素晴らしいです

    1

    私は、PostgreSQLと多くの経験を持っていないが、私の推測では、(空ではなく)と、その列がNOT NULLとしてマークされている場合NULLできる列がNULLあるとき、それはありません意味するビットを保持していることですそのビットは長く必要です。したがって、列のその属性を変更すると、システムはテーブル全体を通過してデータを再配置する必要があります。

    これはDROP TABLEとは大きく異なります。これは単にディスクスペースを使用しなくなったとマークし、おそらくいくつかのメタデータ値を更新するだけです。

    要するに、これらのアクションは非常に異なるアクションであるため、もちろんそれぞれ異なる時間がかかります。

    +0

    'drop not null'はディスクに何も書き込まれません。テーブルに関するメタデータだけを更新します。 not null制約を削除するには数ミリ秒かかります。* not nullの制約を追加することは、データベースと違って**すべての**行を読み込んで値に違反しないことを確認することと同じです。 –

    +0

    それは必ずしも真実ではありません。これが最初の項目が 'NULL'値を許可するように設定されている場合、' NULL'値を持つ列のディスク上のすべての行にビットマップを追加する必要があります。 –

    +0

    私はそうは思わない。あなたはそれについてどんな参考文献を持っていますか?私は 'NOT NULL'と定義された1つの列を持つ1つの列テーブルで試してみました.1000万行のテーブルに' NOT NULL'制約を落としました。 –

    関連する問題