我尝试使用这个看似简单的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)
为什么这会阻止我添加列,我该如何解决?
答案 0 :(得分:7)
我怀疑您预先存在索引损坏或可见性问题。
当你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;
将揭示元组确实存在。
请先阅读this wiki page并采取行动。完成后,请检查您的版本。您是否正在运行或曾经运行过早于9.3.9的PostgreSQL 9.3版本?特别是作为复制品,然后被提升?如果是这样,那可能会解释它,因为已知的多重错误在那里得到修复:
否则,很难说发生了什么。有必要在pageinspect
输出处使用pg_controldata
查看问题堆页面,并且可能在引用这些堆页面的b-tree页面上查看。
答案 1 :(得分:2)
我已经接受了@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;