web-dev-qa-db-ja.com

Postgresは一意のインデックスを作成できませんでした。キーが重複しています

この一見単純な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)

これにより列を追加できなくなったのはなぜですか?どのように修正できますか?

6
Rob Johansen

既存のインデックスの破損または可視性の問題があると思います。

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ツリーページを確認する必要があります。

7
Craig Ringer

@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;
3
Rob Johansen