很长一段时间以来,我们一直被同一张表上的删除和插入有关的死锁问题所困扰。它偶尔发生,但频率一直在增加。它会表现为一个DELETE FROM MYTABLE by unique ID
语句 BLOCKINGINSERT INTO MYTABLE
语句。
最初,我们看不到绑定变量,因为我们使用的是 Hibernate,并且我们无法为 Hibernate 打开 show_sql,因为在应用程序的其他区域中其他 Hibernate 管理的 POJO 上的流量太多了。我们曾认为 Hibernate 可能会在意想不到的时候对它的缓存做一些事情。
最近,我为有问题的表删除了 Hibernate,将其替换为 JDBC,并针对该表记录每次触摸(每次 SELECT/INSERT/UPDATE/DELETE)。
之后,我只看到了 1 个“拦截器”。所以我不知道问题是否通过删除 Hibernate 并通过 JDBC 完成所有事情得到解决。但是,如果我不尝试运行该阻止程序实例,我将失职。
这是我看到的:
- A
DELETE FROM MYTABLE by unique ID
在某一时刻花了将近 10 秒。 - 该
MYTABLE
唯一 ID 在DELETE FROM MYTABLE by Unique ID
. - 那 DELETE 阻止了其他
INSERT INTO
语句。 - “阻塞器”删除语句在 10 秒内完成并自行清除,之后一切正常。
- 它只发生了一次,一天的其余时间
DELETE FROM MYTABLE by Unique ID
将完成亚秒,正如人们所期望的那样。
我与我们的 DBA 确认:
- 我们在有问题的桌子上没有任何
on delete
触发器。 - 该表中的所有 FK 都已编入索引。
当没有对该行的该表进行其他触摸时(没有通过该唯一 ID 进行选择、更新或插入),是否有人对可能导致按唯一 ID 执行删除语句可能需要 10 秒的原因有任何见解/建议?
我意识到这个问题可能没有一个准确和准确的答案,我只是希望有人可以分享他们自己经历的见解或轶事信息。
预先真诚地感谢您。
删除是一个 DML 命令,将数据存储在重做日志中,直到提交删除操作。这意味着如果要通过删除删除的数据稍大[即使搜索时间更短],它将花费更长的时间,因为它将数据移动到重做日志。
所以可能是您的操作花费更长的时间的情况。的行被删除到许多查询可能正在写入重做日志。
考虑一个父/子表,例如客户/订单。
您不能删除有订单的客户。假设客户 123 有一个订单 A123。Fred 对该订单进行了删除,但没有提交。然后“Jane”尝试删除客户端 123。
由于 Fred 的语句可能会回滚,因此无法删除客户端,因为它不允许将订单留在孤立状态。Jane 的删除事务将等待 Fred 的 Delete 对订单的锁定。如果 Fred 提交,那么 Jane's 可以完成。
未提交的更新和插入也会发生类似的情况。可能存在一些丑陋的连接池问题,其中单个前端操作正在使用两个数据库事务来尝试删除客户端及其订单。
虽然没有解释它阻止其他插入到 MYTABLE 中。
如果您可以再次捕捉到它,请尝试查看 V$SESSION 中的 EVENT 以了解长时间运行的会话,因为这将表明它实际上在等待/在做什么。
这可能发生在以下情况: - 您的表 MYTABLE 有一个唯一列 UNIQCOL - 此 MYTABLE.UNIQCOL 被另一个表中的某个列引用,例如 MYTABLE2.UNIQCOL_REF - 此 MYTABLE2.UNIQCOL_REF 未编入索引。
向 MYTABLE2.UNIQCOL_REF 添加(非唯一)索引可以解决问题。
(您说 MYTABLE 中的所有 FK 都已编入索引,但您并没有说所有引用 MYTABLE 的 FK 都已编入索引 - 它们应该是为了避免 MYTABLE2 上的全表锁定)
我会检查 deltee 是否正在使用索引。运行
explain plan
并确保执行计划包含唯一的索引访问路径。这是微不足道的,但上帝在细节中。也许你在这里得到的是一个热点问题。您要删除/插入的行是否具有高连续 pk 值?
b-tree 索引存储为排序索引 - 条目根据它们的值从左到右组织。表中的每个删除语句也从索引中删除一个条目并平衡树 - 因此不仅获得表锁,还获得索引锁。
如果您要删除高 pk 值,假设 pk=1000,并插入 pk = 1001 的新行 - 索引的右侧块正在成为热点,并且您遇到了锁定问题。在这种情况下你所做的就是让你的索引下降。
create index uq1 on table1(pk_columns desc);