我正在运行一个存储过程,它选择我的临时表的值并将它们插入到数据库中,如下所示:
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 -Stored proc +不使用事务+ JDBC callablestatement
在SELECT和随后的INSERT之间是否会发生另一次对相同/不同存储过程的调用,这些过程完成了具有类似数据的INSERT?如果是这样,那么阻止这种情况的最佳方法是什么?
一些想法:我们有很多重复的“客户”实例,他们在生产中同时与这一个SQL Server进行通信,所以我的第一反应是并发问题,但我似乎无法自己复制它。这是我最好的猜测,但它到目前为止无处可去。在我们的临时环境中,这种情况不会发生,因为与生产环境相比,负载是无关紧要的。这是我开始研究并发问题的主要原因。
答案 0 :(得分:5)
错误可能是由两个会话同时执行插入引起的。
使用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
语句将采取适当的锁定,以确保没有其他会话可以潜入“不匹配”检查和“插入”之间。
如果您无法使用merge
,则可以解决客户端问题。确保没有两个插件同时运行。使用mutex或其他同步构造通常很容易做到这一点。