Jus*_*nen 6 sql sql-server deadlock sql-server-2014
我有一个连接到 SQL Server 2014 数据库的应用程序,该数据库将多行合并为一行。应用程序运行时,没有与此数据库的其他连接。
首先,在特定时间跨度内选择一组行。此查询使用与集群查找合并的非集群查找(TIME 列)。
select ...
from FOO
where TIME >= @from and TIME < @to and ...
Run Code Online (Sandbox Code Playgroud)
然后,我们在 c# 中处理这些行并将更改写入单个更新和多个删除,这在每个块中发生多次。这些也使用非聚集索引查找。
begin tran
update FOO set ...
where NON_CLUSTERED_ID = @id
delete FOO where NON_CLUSTERED_ID in (@id1, @id2, @id3, ...)
commit
Run Code Online (Sandbox Code Playgroud)
使用多个并行块运行此程序时出现死锁。我尝试使用ROWLOCKfor updateanddelete但由于某种原因导致比以前更多的死锁,即使块之间没有重叠。
然后我尝试TABLOCKX, HOLDLOCK了update,但这意味着我无法select并行执行我的操作,因此我失去了并行性的优势。
知道如何避免死锁但仍处理多个并行块吗?
鉴于块之间没有行重叠,在这种情况下NOLOCK在 my上使用是否安全select?那么TABLOCKX, HOLDLOCK只会阻止updateand delete,对吗?
或者我应该接受死锁会发生并在我的应用程序中重试查询?
更新(附加信息):到目前为止,所有死锁都发生在update和delete阶段,没有发生在select. 如果我今天不能解决这个问题(之前没有启用正确的跟踪标志),我将尝试获取一些死锁日志。
UPDATE:这是发生在 的两种死锁安排ROWLOCK,它们都只涉及delete语句和它使用的非聚集索引。我不确定这些是否与没有任何表提示的死锁相同,因为我无法重现其中任何一个。
询问 .xdl 是否还需要其他任何内容,我对附加整个内容感到有些厌倦。
关于死锁的一般建议:确保以相同的顺序执行所有操作,即对于不同的进程以相同的顺序获取锁。
您可以在 microsoft.com 上这篇有关最小化死锁的技术文章中找到相同的建议。它被列在第一位是有充分理由的。
- 以相同的顺序访问对象。
- 避免交易中的用户交互。
- 保持交易简短且一批。
- 使用较低的隔离级别。
- 使用基于行版本控制的隔离级别。
- 将 READ_COMMITTED_SNAPSHOT 数据库选项设置为 ON 以使读提交事务能够使用行版本控制。
- 使用快照隔离。
- 使用绑定连接。
卡托提出问题后更新:
在这里如何以相同的顺序获取锁?您对他如何更改 SQL 来做到这一点有什么建议吗?
无论什么环境,死锁总是相同的:两个进程(例如A& B)以不同的顺序获取多个锁(例如X& Y),因此Ais waitingY和Bis waiting X,而Ais waitingX和Bis Holding Y。
它适用于此处,因为DELETEandUPDATE语句隐式获取行或索引范围或表上的锁(取决于引擎认为合适的内容)。
您应该分析您的流程并查看是否存在可以以不同顺序获取锁的情况。如果这没有透露任何信息,您可以使用 SQL Server Profiler 分析死锁:
要跟踪死锁事件,请将死锁图事件类添加到跟踪。此事件类使用有关死锁中涉及的进程和对象的 XML 数据填充跟踪中的 TextData 数据列。SQL Server Profiler 可以将 XML 文档提取到死锁 XML (.xdl) 文件中,您稍后可以在 SQL Server Management Studio 中查看该文件。您可以配置 SQL Server Profiler 将死锁图事件提取到包含所有死锁图事件的单个文件中,或者提取到单独的文件中。