使用 PostgresSQL 版本 11。
让我们采用以下(简化的)名为
examples
的表。
| Column | Type
| id | uuid
| core_id | character varying(255)
| name | character varying(255)
Indexes:
"examples_id_pkey" PRIMARY KEY, btree (core_id)
"examples_core_id_key" UNIQUE CONSTRAINT, btree (core_id)
"examples_id_unique" UNIQUE CONSTRAINT, btree (id)
"id_core_id_unique" UNIQUE CONSTRAINT, btree (core_id, id)
现在,让我们考虑以下 SQL 语句:
INSERT INTO examples
( id, core_id, name)
VALUES
( $id, $coreId, $name)
ON CONFLICT (id, core_id)
DO UPDATE
SET
name = $name
当我尝试两次插入时
我收到
SequelizeUniqueConstraint
错误,如下:
duplicate key value violates unique constraint `examples_core_id_key`
我不明白为什么会发生这种情况,因为我在 ON CONFLICT 子句中指定了
core_id
。因此,我对其进行解释,以便如果缺乏唯一性,只需执行更新即可。
The optional ON CONFLICT clause specifies an alternative action to raising a unique violation or exclusion constraint violation error. For each individual row proposed for insertion, either the insertion proceeds, or, if an arbiter constraint or index specified by conflict_target is violated, the alternative conflict_action is taken.
到目前为止我的假设...我有点想知道这是否是并发问题,因为在生产环境中,我得到以下流程:
不相信这很重要,但我正在使用
sequelize
版本 6.35.2、nodeJs 客户端库运行此查询,如下所示:
await sequelize.query(<query here>)
UPSERT 选择的“仲裁者索引”由
ON CONFLICT
子句中声明的“冲突目标”决定。 说明书:
可以执行独特的索引推断。进行推理时,它由一个或多个组成conflict_target
列和/或index_column_name
表达式,以及可选的index_expression
。全部index_predicate
唯一索引,无论顺序如何,都完全包含table_name
指定的列/表达式 被推断(选择)作为仲裁索引。conflict_target
在您的情况下,
ON CONFLICT (id, core_id)
(仅!)确定多列唯一约束id_core_id_unique
。但您还没有其他三个独特的限制。
是的,您实际上有 4 唯一索引:
"examples_id_pkey" PRIMARY KEY, btree (core_id)
"examples_core_id_key" UNIQUE CONSTRAINT, btree (core_id)
"examples_id_unique" UNIQUE CONSTRAINT, btree (id)
"id_core_id_unique" UNIQUE CONSTRAINT, btree (core_id, id)
索引
examples_core_id_key
是100%冗余的,因为PK索引已经用相同的唯一索引实现了。在您方便的时候尽早删除该索引。
剩下两个唯一的索引不能容忍重复的输入。从多个不同的
UNIQUE
(和 EXCLUSION
)约束捕获唯一违规的唯一方法是通用子句 ON CONFLICT DO NOTHING
。参见:
或者你摆脱其他重叠的约束。您真的需要全部(剩余的)三个吗?