Postgres 合并默默地忽略唯一约束违规

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

以下引用来自此处:https://pganalyze.com/blog/5mins-postgres-15-merge-vs-insert-on-conflict

他主要发表的评论是 MERGE 的缺点 并发的处理是当你同时INSERT时,所以在 在执行 MERGE 语句的同时,有 另一个 INSERT 正在进行,然后 MERGE 可能不会注意到这一点。合并会 进入它的 INSERT 逻辑,然后它会得到一个独特的违规。

我记得,当他最初设计 INSERT ON CONFLICT 时 功能,由于 MVCC 工作方式的限制 Postgres,你不能用它的通用语法来实现 MERGE 以同样可靠的方式工作的选项。如果你想要通用性 MERGE,你必须接受这样一个事实:你可能会变得独一无二 约束违规,当有并发插入时,与 INSERT ON 冲突,它的设计方式带有推测性 插入,保证您获得 INSERT 或 UPDATE 并且 即使存在并发插入也是如此。你可能想要 如果您需要保证,请选择 INSERT ON CONFLICT。

假设我们正在做一个非常巨大的

merge
,这将需要很长时间,并且在合并过程中,发生了上面引用中描述的并发插入,导致插入逻辑期间违反唯一约束。在这种情况下到底发生了什么?它是否会导致整个
merge
查询失败并抛出唯一约束异常?

或者,也许,如果最终插入逻辑中的一行或多行确实发生了唯一约束违规,则只有那些违反唯一约束的行才会被默默地忽略,其余插入将正常进行?

我认为 postgres 的

merge
功能不支持这一点(后者 - 默默地忽略唯一约束违规),但我确实认为这将是对
merge
功能的有价值的补充,因为肯定会有用户(目前的我)谁不希望他们的整个合并插入(或更新)仅仅因为一行或几行违反了唯一约束而失败。

sql postgresql concurrency unique-constraint sql-merge
1个回答
0
投票

我确实使用以下代码运行了一些测试,并且如预期的那样,我发现如果在插入

merge
命令期间发生独特的违规异常,则该独特的违规异常会冒泡并存储整个
merge
查询。

这意味着,例如,如果您正在执行长时间运行的批处理

merge
操作,则
merge
可能会执行 99% 的工作,但是如果即使最后一个插入行导致唯一的违规异常,整个
 merge
查询被回滚,所有工作都随之丢失。

在许多可预见的

merge
用例中,我预计这会非常令人失望,并且远不理想。在我看来,如果
merge
能够提供简单地忽略导致唯一违规异常的行的能力,而不是让整个查询陷入困境,那就更好了。

我认为这个附加功能(忽略在插入查询期间导致唯一违规异常的行)应该添加到 sql 标准和 postgres 中。

用于测试的代码

在一个 sql 进程中运行以下命令:

create table tmp_table (col int);

insert into tmp_table (col)
select *
from generate_series(1, 10000000) as s(i);

CREATE TABLE tmp_table2 (col int unique);

merge into tmp_table2 tt2
using (
  select *
  from tmp_table
) as tt1
on tt2.col = tt1.col
when matched then do nothing
when not matched then
  insert (col)
  values (tt1.col);

在第二个 sql 进程中,在第一个 sql 进程中运行

merge
命令后立即运行以下命令:

insert into tmp_table2 (col)
values (9000000);
© www.soinside.com 2019 - 2024. All rights reserved.