首页 > 解决方案 > INSERT INTO .. SELECT 导致可能的竞争条件?

问题描述

INSERT INTO A
SELECT * FROM B WHERE timestamp > (SELECT max(timestamp) FROM A);

或者,写得不同:

WITH selection AS
    (SELECT * FROM B WHERE timestamp > (SELECT max(timestamp) FROM A))
INSERT INTO A SELECT * FROM selection;

如果这些查询同时运行多次,我是否可能会在 A 中得到重复的行?

Postgres 如何处理这些查询?是一个还是多个?

如果是多个查询(find max(timestamp)[1], select[2] then insert[3])我可以想象这会导致重复的行。

如果这是正确的,将其包装在 BEGIN/END(事务)中会有所帮助吗?

标签: postgresql

解决方案


是的,这可能会导致重复值。

一条语句在该语句开始的时间点看到所有表中数据的一致视图。

将单个语句包装到事务中不会改变这一点(单个语句始终作为原子语句执行,无论涉及的子查询数量如何)。

该语句将永远不会看到来自其他事务的未提交数据(这是您最终会出现重复值的根本原因)。

避免重复值的唯一安全方法是在该列上创建唯一约束(或索引)。在这种情况下,如果这样的值已经存在,则 INSERT 将导致错误。

如果要避免错误,请使用insert ... on conflict


推荐阅读