この一見単純なSQLを使用して、Postgres 9.3データベースのテーブルに列を追加しようとしています。
ALTER TABLE quizzes ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT false;
ただし、次のエラーが発生します。
ERROR: could not create unique index "quizzes_pkey"
DETAIL: Key (id)=(10557462) is duplicated.
不思議なことに、実際には行なしがそのIDにあります(これは主キーなので、重複してはいけません)。
SELECT id FROM quizzes WHERE id = 10557462;
id
----
(0 rows)
実際、そのIDは何とかスキップされているようです。
SELECT id FROM quizzes WHERE id > 10557459 ORDER BY id LIMIT 4;
id
----------
10557460
10557461
10557463
10557464
(4 rows)
これにより列を追加できなくなったのはなぜですか?どのように修正できますか?
既存のインデックスの破損または可視性の問題があると思います。
ALTER TABLE ... ADD COLUMN ... DEFAULT ...
を実行すると、テーブル全体が書き換えられます。これにより、ヒープ上の問題に気づくプロセスで、すべてのインデックスが再構築されます。
おそらく、テーブルのVACUUM FULL
が同じエラーを生成することがわかります。
私はそれを期待します
BEGIN;
SET LOCAL enable_indexscan = off;
SET LOCAL enable_bitmapscan = off;
SET LOCAL enable_indexonlyscan = off;
SELECT ctid,xmin,xmax,id FROM quizzes WHERE id = 10557462;
ROLLBACK;
タプルが実際に存在することを明らかにします。
最初に このWikiページ を読んで実行してください。完了したら、バージョンを確認してください。 9.3.9より前のバージョンのPostgreSQL 9.3を実行している、または実行したことがありますか?特にその後宣伝されたレプリカとして?その場合は、そこで修正された既知のmultixactバグが原因であると考えられます。
そうでなければ、何が起こっているのかを言うのは難しい。 pageinspect
を使用して、問題のあるヒープページをpg_controldata
の出力で確認し、場合によってはそれらのヒープページを参照するBツリーページを確認する必要があります。
@Craig Ringerの回答を受け入れました。それがなければ問題を解決できなかったからです。それが他の誰かを助ける場合に備えて、私が問題を解決するために使用した正確なクエリを次に示します(幸運なことに、重複は削除できます)。
BEGIN;
SET LOCAL enable_indexscan = off;
SET LOCAL enable_bitmapscan = off;
SET LOCAL enable_indexonlyscan = off;
DELETE FROM quizzes WHERE id = 10557462;
COMMIT;
その後、私の元のクエリはようやく成功しました:
ALTER TABLE quizzes ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT false;