PostgreSQL报PG::UniqueViolation唯一键冲突但无重复数据如何解决
问题根因
你收到的报错指向的唯一约束和你贴出的已创建索引不是同一个:你创建的是user_id、gender、deleted_at三列联合的索引,而报错触发的是仅user_id+gender两列的唯一索引index_comms_applications_on_user_id_and_gender,所以删除三列索引无法解决问题。
解决步骤
- 第一步:确认表中现存的约束/索引
登录PostgreSQL执行命令查看表结构:
确认列表中是否存在名为\d comms_applicationsindex_comms_applications_on_user_id_and_gender的唯一索引,该索引是报错的直接来源。 - 第二步:删除多余的两列唯一索引
如果你不需要对user_id+gender做全局唯一限制,直接执行SQL删除该索引:
同时要检查Rails迁移文件,删除对应创建该两列唯一索引的代码,避免后续部署时重新生成该索引。DROP INDEX IF EXISTS index_comms_applications_on_user_id_and_gender; - 第三步:验证你的业务逻辑索引是否符合预期
如果你原本的需求是「仅未删除的记录需要满足user_id+gender唯一」,你创建的三列联合索引是生效的:因为逻辑删除的deleted_at字段为NULL时才代表有效记录,NULL在PG的唯一校验中会被视为不同的值,所以多条删除后的重复user_id+gender记录不会触发冲突,仅会校验有效记录的唯一性。 - 第四步:处理删除索引后仍报错的异常场景
如果确认索引已经删除还是收到报错,检查两类情况:- 报错实际触发自其他关联表的触发器/外键约束,仔细查看报错的完整上下文,确认冲突的表是否为
comms_applications - Rails缓存了旧的schema信息,执行
rails db:schema:dump刷新schema缓存后重启服务即可。
- 报错实际触发自其他关联表的触发器/外键约束,仔细查看报错的完整上下文,确认冲突的表是否为
关于索引数据清理的疑问
PostgreSQL的索引数据和表数据是实时强一致的,不存在索引残留旧数据的情况,不需要手动清理索引存储的内容:索引存在时会自动校验当前表所有数据的唯一性,索引删除后对应的唯一约束直接失效。
内容的提问来源于stack exchange,提问作者Kingsley Simon
相关产品推荐
相关产品推荐

