长时间选择时事务死锁



我有一个夜间作业,它执行一个存储过程,该过程遍历一个表并获取要插入到另一个表中的记录。

过程持续时间约为 4-5 分钟,其中它对具有 ~3M 条记录的表执行 6 个选择。

当此过程运行时,会从另一个尝试更新同一表的存储过程引发异常:

  1. 事务(进程 ID 166)在锁定资源上死锁 另一个进程,并被选为死锁受害者。重新运行 交易。

  2. 执行超时已过期。 在 操作完成或服务器没有响应。--->System.ComponentModel.Win32Exception (0x80004005):等待操作 超时

我已阅读为什么使用读取未提交的隔离级别? 问题,但没有得出最适合我的情况的结论,正如其中一条评论所述:

"作者似乎暗示读取未提交/无锁将返回 无论上次提交什么数据。我的理解是未承诺的 将返回上次设置的任何值,即使从未提交 交易。如果是这样,结果将不会是检索数据"几个 秒过时了"。它会(或者至少可以,如果交易 写入您读取的数据被回滚)正在检索的数据 不存在或从未提交">

考虑到我只关心夜间作业开始时的行状态(同时的更新将在下一个中计算) 什么是最合适的方法?

事务(进程 ID 166)在锁定资源上死锁 另一个进程,并被选为死锁受害者。重新运行 交易。

这通常发生在您读取数据并打算稍后通过放置共享锁来更新它时,以下 UPDATE 语句无法获取必要的Update Locks,因为它们已经被在不同会话中获取的共享锁阻止,从而导致死锁。

要解决此问题,您可以使用如下所示UPDLOCK选择记录

SELECT * FROM [Your_Table] WITH (UPDLOCK) WHERE A=B

这将提前对记录进行必要的更新锁定,并将停止其他会话以获取记录上的任何锁定(共享/独占),并防止任何死锁。

死锁(Cycle Deadlock)的另一个常见原因是由于您在查询中放置的语句的顺序,最终每个查询在不同的事务中等待另一个查询。对于此类方案,您必须访问查询并修复排序问题。

执行超时已过期。在 操作完成或服务器没有响应。--->System.ComponentModel.Win32Exception (0x80004005):等待操作 超时

这是非常清楚的,您需要在查询性能上下功夫,并尽可能少地保持记录锁定。

最新更新