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