我有一个夜间工作,它执行一个遍历表的存储过程并获取要插入另一个表的记录。
程序持续时间约为4-5分钟,在该表中,在具有~3M记录的表格上执行6次选择。
当此过程正在运行时,从另一个尝试更新同一个表的存储过程抛出异常:
事务(进程ID 166)在锁定资源上死锁 另一个进程并被选为死锁受害者。重新运行 事务。
执行超时已过期。超时时间过去之前 完成操作或服务器没有响应。 ---> System.ComponentModel.Win32Exception(0x80004005):等待操作 超时
我已阅读Why use a READ UNCOMMITTED isolation level? 个问题,但没有得出最符合我情景的结论,正如其中一条评论所述:
"作者似乎暗示读取未提交/没有锁定将返回 上次提交的数据。我的理解是未经承认的 将返回最后设置的任何值,即使是未提交的 交易。如果是这样,结果将不会检索数据"一些 秒过时"。它会(或至少如果交易 写入您读取的数据后退了)检索数据 不存在或从未被提交过#34;
考虑到我只关心夜间工作开始时行的状态(同时更新将在下一个计算中) 什么是最合适的方法?
答案 0 :(得分:3)
事务(进程ID 166)在锁定资源上死锁 另一个进程并被选为死锁受害者。重新运行 事务。
这通常发生在您稍后通过放置共享锁来读取数据以更新它时,以下UPDATE语句无法获取必要的Update Locks
,因为它们已被获取的共享锁阻止在导致僵局的不同会话中。
要解决此问题,您可以使用UPDLOCK
选择记录,如下所示
SELECT * FROM [Your_Table] WITH (UPDLOCK) WHERE A=B
这将提前对记录进行必要的更新锁定,并将停止其他会话以获取记录上的任何锁定(共享/独占),并防止出现任何死锁。
死锁的另一个常见原因(Cycle Deadlock
)是由于您在查询中放入的语句的顺序,最终每个查询在不同的事务中等待另一个查询。对于此类场景,您必须访问查询并修复排序问题。
执行超时已过期。超时时间过去之前 完成操作或服务器没有响应。 ---> System.ComponentModel.Win32Exception(0x80004005):等待操作 超时
这很清楚,您需要处理查询性能,并尽可能减少记录锁定。