具有多个唯一索引的UPSERT(INSERT INTO ... ON CONFLICT)

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

使用 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  

当我尝试两次插入时

  • 插入 1 ('abc', 'abc', 'somename')
  • 插入 2 ('abc' 'abc', 'somename')

我收到

SequelizeUniqueConstraint
错误,如下:

duplicate key value violates unique constraint `examples_core_id_key`

我不明白为什么会发生这种情况,因为我在 ON CONFLICT 子句中指定了

core_id
。因此,我对其进行解释,以便如果缺乏唯一性,只需执行更新即可。

基于 postgres 文档 v11

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.

到目前为止我的假设...我有点想知道这是否是并发问题,因为在生产环境中,我得到以下流程:

  • 同时收到内容相同的消息1和消息2。
  • 消息 1 通过,消息 2 失败,并出现续集验证错误。
  • 消息 2 被重新处理,然后通过。

不相信这很重要,但我正在使用

sequelize
版本 6.35.2、nodeJs 客户端库运行此查询,如下所示:

await sequelize.query(<query here>) 
postgresql sequelize.js upsert postgresql-11
1个回答
0
投票

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
。参见:

或者你摆脱其他重叠的约束。您真的需要全部(剩余的)三个吗?

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