1

Transaction ABORTed due to Deadlock最近,当我们去更新我们的一个表中的记录时,我们遇到了错误。有东西在这张桌子上加了一把锁,它没有被释放,但我花了几天的时间试图追踪它,但它仍然让我难以捉摸。

虽然错误是随机的,但我确实知道我需要重复哪些重复循环才能最终触发它。但是,我查询了 dbc.DBQLogTbl 并查看了在错误发生前后 2 分钟执行的所有 SQL,并且在没有访问锁的情况下似乎没有从任何表中进行选择。此外,在错误发生后,我将按 F5 将 Web 表单重新发布回服务器以重复完全相同的更新集,它会起作用。

我的预感是我们的 ASP.NET 应用程序之外的某个进程正在锁定表,因为我已经检查了我们的应用程序正在执行的所有 SQL。我认为必须有一种方法来找出执行了哪些特定的 SQL 并在表上放置了锁。

2012 年 8 月 9 日附加信息: 根据我在查询dbc.DBQLogTbl和订购时看到的内容,在同一事务中按此顺序发生以下所有情况firststeptime

  • 更新员工表
  • 锁定访问行 select * from employeesecurity where empid = X (执行此操作以获取当前员工记录以查看是否有任何更改)
  • 如果有变化,更新上述员工安全记录
  • 更新employeeconfig表(这里总是出现死锁错误)

我之前没有提到这一点,但是死锁错误发生在我根本没有从中选择的表上。当页面加载时,我确实从一个employeeconfig 视图中读取,但locking row for access在视图中指定。

回答 Rob 的 4 个问题:

  • 这只是一笔交易。
  • 正如我在最新更新中所述,被锁定的表甚至不是从中选择的表。
  • 所有查询使用locking row for access
  • 我们从视图中选择employeeconfig。此视图使用 . 从employeeconfig表中进行选择locking row for accesslocking row for access我们在查询视图本身时不使用。

至于处理死锁,我宁愿没有代码只是尝试重新提交它,因为这似乎是一个需要修复的问题。正如你所说,Rob,我的访问权限可能dbc.DBQLogTbl是有限的,所以我可能无法看到正在发生的一切。我一直在联系 DBA,今天将再次跟进。

4

2 回答 2

3

识别中止的事务

死锁条件应该导致导致死锁的两个事务都被中止。我通常会看到 Informatica 的下推优化尝试并行创建临时视图并在创建视图所需的 DBC 表上出现死锁。与您的情况一样,我们的 Informatica 情况完全是随机的。由于僵局,我们可以持续数周或数月而不会中止。

您可以通过在 DBQL 日志表中查询带有ErrorCode = 2631编辑:已修复错误代码)和ORDER BY StartTime DESC. 这将为您提供由于死锁而中止的每个事务。如果没有通过排序配对,导致死锁的事务对应该相当接近。

如果您的 DBA 以任何方式限制了针对历史 DBQL 数据的视图,则可能会妨碍您找到根本原因的能力。如果是这种情况,您将需要与您的 DBA 团队一起查明问题。由于给定查询的 SQLText 中包含的信息,查询信息仅限于开发人员的情况并不少见。这只是要考虑询问您的查询是否没有产生任何结果。

确定可能发生中止事务的原因

注意:这不是一个详尽的列表。

像这样的死锁条件更糟糕的是它们通常是随机发生的。墨菲定律规定,这些随机事件将发生在您睡觉、度假或其他您不希望被打扰的活动中。根据您的具体情况,您可以简单地重新提交已死锁的事务。

这将要求您首先了解您是如何达到死锁条件的。

  • 如果是两个事务试图操纵相同的记录,您的数据模型是否支持缓慢变化的维度,以便您记录每次发生的变化?
  • 如果是读取事务和更新事务访问同一条记录,您是否可以调整锁定粒度和持续时间以最小化机会?
  • 你是使用ACCESS还是READ锁定?
  • 您的SELECT语句是否通过使用ROWHASH ACCESS锁定的 1:1 视图访问表,从而允许优化器将锁定从最精细的级别升级到相关事务所需的级别?(例如LOCKING ROW FOR ACCESS SELECT * FROM DBC.DBCInfo;
  • 删除了关于更新语句的行锁定的建议。

处理中止的事务

根据您的死锁情况,您可以选择让您的进程尝试重新提交失败的事务预先确定的次数。您可能会遇到这样一种情况,即一个进程可能会重新提交,而另一个进程可能必须保持失败状态,以便其他人在继续之前进行验证。前者可能是你的 Web 应用,后者可能是复杂的 ETL 流,不能盲目重启。

您应该在某处记录发生这种情况,或者使用其他一些报告机制来跟踪这些事件。

于 2012-08-08T00:44:42.957 回答
0

在关系数据库中,被中止的事务本身不是错误,而仅仅是请求客户端从头开始重试事务,因为不同的并发事务可能已经改变了发出现在中止事务的客户端已经观察到的条件. 通过偶尔允许事务中止(并由客户端重试),底层关系数据库可以进行显着的性能优化,例如允许许多事务同时运行,即使这会导致死锁的可能性很小。

在这些情况下,为什么数据库服务器不重试事务本身?因为客户端可能正在使用从事务中的一个查询返回的数据来影响在同一事务中的后续更新中要执行哪些类型的更新。因此,在交易被中止的罕见(但完全正常和预期)的情况下,重试交易的责任在于客户端。

所以答案是:中止的事务是完全正常的,你只是应该从客户端重试它们。但正如 Rob 所指出的,这可能容易或困难,具体取决于您正在执行的事务类型(例如,如果您正在执行 2 小时的 ETL 流程,您可能想弄清楚如何减少死锁的可能性) .

于 2013-10-06T18:22:27.083 回答