6

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

 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 通信,所以我的第一反应是并发问题,但我自己似乎无法复制它。这是我最好的猜测,但到目前为止还没有。这不会发生在我们的暂存环境中,与生产环境相比,负载微不足道。这是我开始研究并发问题的主要原因。

4

1 回答 1

5

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

您可以使用MERGE使您的 SQL 代码更安全。正如 Aaron Bertrand 的评论所说(谢谢!),您必须包含一个with (holdlock)提示以确保merge真正安全

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

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

如果你不能使用merge,你可以在客户端解决问题。确保没有两个插件同时运行。这通常很容易通过互斥锁或其他同步结构来实现。

于 2013-03-13T14:52:21.913 回答