Postgres 无法创建唯一索引,键重复
Postgres could not create unique index, key is duplicated
我正在尝试使用这个看似简单的 SQL:
向我的 Postgres 9.3 数据库中的 table 添加一列
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 ...
时,它会进行完整的 table 重写。这将重建所有索引,在此过程中注意到堆上的问题。
您可能会发现 table 上的 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 采取行动。完成后,检查您的版本。您 运行 宁或曾经 运行 PostgreSQL 9.3 版本早于 9.3.9 吗?尤其是作为当时推广的复制品?如果是这样,这可能是由于已知的 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;
我正在尝试使用这个看似简单的 SQL:
向我的 Postgres 9.3 数据库中的 table 添加一列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 ...
时,它会进行完整的 table 重写。这将重建所有索引,在此过程中注意到堆上的问题。
您可能会发现 table 上的 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 采取行动。完成后,检查您的版本。您 运行 宁或曾经 运行 PostgreSQL 9.3 版本早于 9.3.9 吗?尤其是作为当时推广的复制品?如果是这样,这可能是由于已知的 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;