【发布时间】:2017-03-27 21:23:35
【问题描述】:
我有一个连接到 SQL Server 2014 数据库的应用程序,该数据库将多行合并为一个。应用程序运行时没有与此数据库的其他连接。
首先,在特定时间范围内选择一大块行。此查询使用与集群查找合并的非集群查找(TIME 列)。
select ...
from FOO
where TIME >= @from and TIME < @to and ...
然后,我们在 c# 中处理这些行并将更改写入单个更新和多个删除,每个块会发生很多次。这些也使用非聚集索引查找。
begin tran
update FOO set ...
where NON_CLUSTERED_ID = @id
delete FOO where NON_CLUSTERED_ID in (@id1, @id2, @id3, ...)
commit
在使用多个并行块运行此程序时,我遇到了死锁。我尝试将ROWLOCK 用于update 和delete,但由于某种原因,这导致了比以前更多的死锁,即使块之间没有重叠。
然后我在update 上尝试了TABLOCKX, HOLDLOCK,但这意味着我无法并行执行我的select,因此我失去了并行性的优势。
知道如何避免死锁但仍能处理多个并行块吗?
在这种情况下,在我的select 上使用NOLOCK 是否安全,因为块之间没有行重叠?那么TABLOCKX, HOLDLOCK 只会屏蔽update 和delete,对吗?
或者我应该接受会发生死锁并在我的应用程序中重试查询?
更新(附加信息):到目前为止,所有死锁都发生在 update 和 delete 阶段,select 没有发生。如果我今天无法解决这个问题,我会尝试获取一些死锁日志(之前未启用正确的跟踪标志)。
更新:这是ROWLOCK 发生的两种死锁安排,它们都只涉及delete 语句和它使用的非聚集索引。我不确定这些是否与在没有任何表提示的情况下发生的死锁相同,因为我无法重现其中任何一个。
请问.xdl 是否还需要其他任何东西,我有点厌倦了附加整个东西。
【问题讨论】:
-
您是否尝试在选择过程中声明
UPDLOCK?这样,当您更新/删除时,锁已经存在,这应该可以防止您陷入死锁。如果可能的话,与我们分享一些死锁日志记录的详细信息。 -
你能把所有的处理都移到一个存储过程中吗?您可能也可以通过简单地打开快照隔离来解决这个问题,但这实际上取决于您在做什么。
-
@Jens 不幸的是,我现在无法获取死锁日志。似乎所有因死锁而失败的线程都处于
update和delete阶段,因此更改select锁不太可能影响这种情况。不幸的是,我没有任何死锁日志,我会看看是否可以为下一次尝试启用死锁跟踪标志。 @Nick.McDermaid 不幸的是不能使用快照隔离。 -
"multiple parallel chunks" >> 这是一个单一的进程,它从不同的线程产生多个任务来执行此操作,希望加快进程?您不会从这种工作方式中获得任何好处。最好从一个“脚本”或“过程”中执行此操作,并让 SQL Server 在它认为合适的情况下进行并行化。
-
如果我们可以这样称呼它,您应该制定“算法”,在您的问题中一目了然。在什么线程上发生了什么,控制流和事件顺序是什么......从你写的内容来看有点不清楚。 SELECT 的结果是什么?一个身份证;还是很多ID?如果您回答多个 ID,您会做什么:每个 ID 的事务或所有 ID 的事务。是SELECT一个块的结果,还是你有很多选择,每个选择一个块。 SELECT 是事务的一部分吗?为什么在一个事务中只更新一个 ID 而删除其他几个 ID?等等。
标签: sql sql-server sql-server-2014 deadlock