提问人:Nick 提问时间:11/14/2023 更新时间:11/16/2023 访问量:54
Postgres 合并静默忽略唯一约束冲突
Postgres merge silently ignore unique constraint violation
问:
以下引文来自这里:https://pganalyze.com/blog/5mins-postgres-15-merge-vs-insert-on-conflict
他基本上发表的评论是 MERGE 的缺点 并发的处理是,当你并发 INSERT 时,所以在 在执行 MERGE 语句的同时,有 另一个 INSERT 正在进行,那么 MERGE 可能不会注意到这一点。MERGE 将 进入其 INSERT 逻辑,然后它会得到一个唯一的冲突。
我记得,当他最初设计 INSERT ON CONFLICT 时 功能,由于 MVCC 工作方式的这种限制 Postgres,您不能使用其通用语法和 以同样可靠的方式工作的选项。如果你想要通用性 的 MERGE,你必须接受这样一个事实,即你可能会得到独特的 约束冲突(当存在并发插入时)与 INSERT ON CONFLICT,它的设计方式及其投机性 insertions,保证您获得 INSERT 或 UPDATE 和 即使存在并发插入,也是如此。您可能希望 如果需要保证,请选择 INSERT ON CONFLICT。
然后假设我们正在做一个非常大的事情,这将需要很长时间,并且在合并过程中,会发生上面引用中描述的并发插入,导致插入逻辑期间唯一约束冲突。在这种情况下究竟会发生什么?它是否会导致整个查询失败并引发唯一约束异常?merge
merge
或者,如果最终插入逻辑中的一行或多行确实发生了唯一约束冲突,则只有那些具有唯一约束冲突的行才会被静默忽略,而其余的插入将照常进行?
我认为 postgres 的功能不支持这一点(后者 - 默默地忽略唯一约束冲突),但我确实认为这将是对功能的宝贵补充,因为肯定会有用户(我目前)不希望他们的整个合并插入(或更新)失败仅仅因为一行或几行具有唯一的约束冲突。merge
merge
答:
我确实使用以下代码运行了一些测试,并且我发现,正如预期的那样,如果在插入命令期间发生唯一违规异常,则此唯一违规异常会冒泡并导致整个查询。merge
merge
这意味着,例如,如果您正在执行长时间运行的批处理操作,则可能会执行 99% 的工作,但是,如果即使是最后一个插入行也会导致唯一的冲突异常,则整个查询将被回滚,并且所有工作都会随之丢失。merge
merge
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);
评论