Postgres 无法创建唯一索引,键重复

问题描述 投票:0回答:3

我正在尝试使用这个看似简单的 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)

为什么这会阻止我添加列,如何修复它?

sql postgresql alter-table
3个回答
17
投票

我怀疑您已经存在索引损坏或可见性问题。

当您

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;

将揭示元组确实存在。

请首先阅读此维基页面并采取行动。完成后,检查您的版本。您正在运行或曾经运行过 9.3.9 之前的 PostgreSQL 9.3 版本吗?尤其是作为当时推广的复制品?如果是这样,这可能是由于修复了已知的 multixact 错误而导致的:

否则,很难说发生了什么。有必要使用

pageinspect
、在
pg_controldata
输出以及可能引用这些堆页面的 B 树页面来查看问题堆页面。


10
投票

我已经接受了@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;

0
投票

对我来说,我正在将列从 text 更新为 citext。我在文本字段上有一个索引,其中包含不同区分大小写的匹配值。当我尝试将文本列更改为 citext 时,索引被复制(因为大小写不再重要)并引发错误。

解决方案是确保该字段中不存在不区分大小写的重复项。

© www.soinside.com 2019 - 2024. All rights reserved.