UPSERT(INSERT INTO ... ON CONFLICT)具有多个唯一索引 - 并发和唯一约束违规

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

我在 PostgreSQL 11 数据库中有以下(简化的)表

examples

| Column  | Type 
| id      | uuid
| core_id | character varying(255)
| name    | character varying(255)

Indexes: 
  "examples_core_id_pkey" PRIMARY KEY, btree (core_id)
  "examples_core_id_key" UNIQUE CONSTRAINT, btree (core_id)
  "examples_id_unique" UNIQUE CONSTRAINT, btree (id)

现在,让我们考虑以下 SQL 语句:

INSERT INTO examples
( id, core_id, name)
VALUES
( $id, $coreId, $name) 
ON CONFLICT (core_id)
DO UPDATE 
SET 
  name = $name  

当我尝试两次插入时

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

我有时会收到

SequelizeUniqueConstraint
错误:

重复的键值违反了唯一约束

examples_id_unique

我不明白为什么会发生这种情况,因为我在

core_id
子句中指定了
ON CONFLICT
。因此,我对其进行解释,以便如果 core_id 缺乏唯一性,只需执行
UPDATE
并且不要触摸
id
。我认为 postgres 在这些情况下只会检查仲裁者索引 (core_id) 并运行更新。

基于 postgres 文档 v11

可选的 ON CONFLICT 子句指定了替代操作 引发唯一违规或排除约束违规错误。 对于建议插入的每个单独行,插入 继续,或者,如果仲裁器约束或索引指定 违反了conflict_target,则采取替代conflict_action。

我想知道这是否是一个并发问题,因为在生产环境中,我得到以下流程:

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

这似乎与这个问题非常相似具有唯一约束的INSERT ON CONFLICT DO UPDATE SET(UPSERT)语句在并发运行时会生成约束违规但尚未找到此问题的解决方案。

sql postgresql database-design upsert postgresql-11
1个回答
1
投票

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

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

UNIQUE
上有
(core_id, id)
的表来说,
PRIMARY KEY
上的
(core_id)
约束没有什么意义。对于半标准化设计来说,多个
UNIQUE
约束是罕见的例外......

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