SQl Server死锁,带有简单的更新语句

时间:2014-10-16 23:40:54

标签: sql-server sql-update database-deadlocks

使用SQL Server 2008 R2当同时运行相同的更新语句(具有不同参数)时,我会遇到死锁。这是死锁图(抱歉无法在此处发布图片):

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客户端中处理错误的方式。它在重试时肯定是成功的,但如果可能的话,最好避免死锁。

由于

1 个答案:

答案 0 :(得分: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 
    }
}