2014-10-16 80 views
0

使用SQL Server 2008 R2当同一个更新语句(使用不​​同参数)并发运行时,我遇到死锁。这里是死锁图形(抱歉无法张贴在这里的图像还):使用简单更新语句SQl服务器死锁

http://i.stack.imgur.com/E6JBK.png

这里是实际的执行计划:

http://i.stack.imgur.com/emm9i.png

更新是这样的:

exec sp_executesql N'UPDATE mapping.IssuerAlternateName 
SET 
    UseCount = UseCount + 1, 
    MostRecentlyAppeared = GETDATE(), 
    MostRecentlyAppearedUnderlyingAssetName = @p1 
WHERE ID = @p0 
',N'@p0 int,@p1 nvarchar(4000)',@p0=1234,@p1=N'blah blah blah' 

如果我已经正确理解了事情,我们正在尝试从相同索引读取和写入(PK_IssuerAlternateName_1)

有什么办法可以解决这个问题吗?我想知道,如果向主键添加附加索引并使用WITH INDEX可能会通过停止读取PK_IssuerAlternateName_1(抱歉在执行计划屏幕截图中截断全名)来解决该问题。

或者是最好的选择只是为了生活并重试交易,这是当前在.NET客户端处理错误的方式。重试肯定是成功的,但如果可能的话,避免死锁是一件好事。

感谢

+0

你目前是否在交易中包装这个?如果是这样,你使用的隔离级别是什么? – mallocation 2014-10-17 01:03:09

+0

使用LINQ2SQL调用context.ExecuteCommand()... – MT1 2014-10-17 05:57:07

回答

0

在类似这样的情况,我已经使用了UPDLOCK提示让数据库知道我打算更新此行。这不是暗示UPDATE声明。没有锁定提示,它将首先获取“共享”锁定,然后尝试升级。但是,这会在某些情况下导致死锁。

您需要在自己的TransactionScope中执行此操作,以确保一切正常。

var sql = @"UPDATE mapping.IssuerAlternateName with (UPDLOCK) 
SET 
    UseCount = UseCount + 1, 
    MostRecentlyAppeared = GETDATE(), 
    MostRecentlyAppearedUnderlyingAssetName = @p1 
WHERE ID = @p0"; 

var options = new TransactionOptions() 
{ 
    IsolationLevel = IsolationLevel.ReadCommitted // don't use Serializable! 
}; 

using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew, options)) 
{ 
    using (var context = new YourDbContext()) 
    { 
     // execute your command here 
    } 
} 
+0

因此,如果获取更新锁定而不是共享锁定,则下一个进程将只等待此语句在启动之前完成?对不起,我不是DBA ... – MT1 2014-10-17 18:26:44

+0

是的。而且我也不是DBA。我在队列环境中有类似的经历。 – mallocation 2014-10-17 18:36:18