【问题标题】:SQl Server deadlock with simple update statement带有简单更新语句的 SQL Server 死锁
【发布时间】:2014-10-16 23:40:54
【问题描述】:

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

谢谢

【问题讨论】:

  • 您当前是否将其包装在事务中?如果是这样,您使用的是哪种隔离级别?
  • 使用 LINQ2SQL 调用它所以 context.ExecuteCommand()...

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


【解决方案1】:

在与此类似的情况下,我使用了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 
    }
}

【讨论】:

  • 那么如果它得到一个更新锁而不是一个共享锁,那么下一个进程会在开始之前等待这个语句完成吗?抱歉,我不是 DBA...
  • 是的。而且我也不是 DBA。我刚刚在队列环境中有过类似的经历。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-14
  • 1970-01-01
  • 2019-09-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多