在SQL Server 2014中,“事务(进程ID)因与另一个进程发生锁资源死锁而被选择为死锁牺牲者”。

3

我有一个更新存储过程,我从C#代码中调用它,并且我的代码同时在3个线程中运行。更新语句通常会抛出错误:“事务(进程ID)在与另一个进程锁定资源时发生死锁,并被选择为死锁牺牲者。重新运行事务。” 我该如何在SQL Server 2014或C#代码中解决这个问题?

更新存储过程:

ALTER PROCEDURE sp_UpdateSP
@RecordID nvarchar(50),
@FileNetID nvarchar(50),
@ClassName nvarchar(150) 

 AS

Begin tran t1
UPDATE MYTABLE SET FilenetID=@FileNetID, DOCUMENT_TYPE=@ClassName, CONTROLID='FileAttach' where OTRECORDID=@RecordID 
Commit tran t1

表索引: 非唯一,非聚集的 OTRECORDID 升序 nvarchar(255)

谢谢


这个程序本身不会引起任何死锁。你是否在其他线程的过程或查询中使用了这个表? - Serkan Arslan
不要以sp_开头命名你的存储过程。sp_前缀仍然是个禁忌吗?- Aaron Bertrand - SqlZim
你说 otrecordidnvarchar(255)。那么为什么 @RecordId 参数是 nvarchar(50) - SqlZim
需要完整的表DDL,包括索引和执行计划,才能真正看出发生了什么。这个更新是否预计影响多行?如果不是,为什么OTRECORDID上没有唯一索引呢? - David Browne - Microsoft
2个回答

0

这可能不是确切的答案,但如果您想要一个解决问题的变通方法,请运行服务:

Win + R > 输入 services.msc

找到 SQL Server 服务 - 如果您只有一个实例,则大多数情况下命名为 SQL Server (MSSQLSERVER) - 然后重新启动服务,现在死锁事务已经消失,您可以继续工作。


0

我怀疑问题是由于SQL在表上执行扫描,因为它认为这比在索引上执行查找然后进行键值查找来更新行更快。

你可以通过使用FORCESEEK提示来防止这些扫描并强制SQL执行查找操作。

你的代码将变成:

Begin tran t1
UPDATE mt SET FilenetID=@FileNetID, DOCUMENT_TYPE=@ClassName, CONTROLID='FileAttach' FROM MYTABLE mt WITH(FORCESEEK) where OTRECORDID=@RecordID 
Commit tran t1

这种方法比扫描慢,但可以降低死锁的概率。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接