sql - INSERT INTO .. SELECT .. 违反唯一约束

标签 sql sql-server unique-constraint

我正在运行一个存储过程,它选择我的临时表中的值并将它们插入数据库,如下所示:

 INSERT INTO emails (EmailAddress)   (
     SELECT
       DISTINCT eit.EmailAddress
     FROM #EmailInfoTemp eit
       LEFT JOIN emails ea
         ON eit.EmailAddress = ea.EmailAddress
     WHERE ea.EmailAddressID IS NULL   )

在极少数情况下(在每分钟处理数千个请求的服务器上大约每几个小时一次),我会在 EmailAddress 列的索引上收到唯一约束错误“违反 UNIQUE KEY 约束...”。

我可以确认我没有传递重复的值。即使我是,也应该被 DISTINCT 捕获。

-SQL Server 2008 -存储过程+不使用事务+JDBC可调用语句

在 SELECT 和随后的 INSERT 之间,是否会发生另一个对相同/不同存储过程的调用,该存储过程使用类似数据完成了 INSERT?如果是这样,防止这种情况的最佳方法是什么?

一些想法:我们有许多重复的“客户端”实例,它们在生产中同时与这个 SQL Server 进行通信,所以我的第一 react 是并发问题,但我自己似乎无法复制它。这是我最好的猜测,但到目前为止还没有任何结果。这种情况不会发生在我们的临时环境中,与生产环境相比,负载微不足道。这是我开始研究并发问题的主要原因。

最佳答案

该错误可能是由两个 session 同时执行插入引起的。

您可以使用 MERGE 让您的 SQL 代码更安全。正如 Aaron Bertrand 的评论所说(谢谢!),you have to include a with (holdlock) hint to make merge really safe .

; merge emails e with (holdlock)
using   #EmailInfoTemp eit
on      e.EmailAddress = eit.EmailAddress
when    not matched then insert
        (EmailAddress) values (eit.EmailAddress)

merge 语句将采取适当的锁定,以确保没有其他 session 可以潜入其“不匹配”检查和“插入”之间。

如果您无法使用merge,您可以在客户端解决问题。确保没有两个插入同时运行。这通常可以通过 mutex 轻松完成。或其他同步结构。

关于sql - INSERT INTO .. SELECT .. 违反唯一约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15388287/

相关文章:

sql - ESQL - 有谁知道可以为 ESQL 提供静态代码分析的工具吗?

Spring Data Neo4j -repository.save 和 @Indexed(unique=true)

java - 为什么@UniqueConstraint在 hibernate 中不起作用?

mysql - 如何在一个更新sql查询中乘以当前数据库行值

mysql - 如何根据sql表的2个字段对显示总值的记录进行分组?

php - Mysql在2个表左连接中搜索

mysql - 在 SSIS 包中使用临时表

sql-server - 独立于图表数据的 SSRS 轴名称

sql-server - 如何在列上添加 HIDDEN 属性?

mysql - 尽管 where 子句中的列上存在索引,但事件记录查找间歇性变慢