我正在运行一个存储过程,它选择我的临时表中的值并将它们插入数据库,如下所示:
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/