我试图了解为什么我的数据库会出现死锁。跟踪告诉我同一张表上的两个更新正在锁定。In table 是事务中要写入的第一个表,之前只发生了一些读取。更新/插入以批处理方式完成。也用于标识要更新的行的键使用 b+-tree 进行索引。该键在其他表中也充当外键。在这些其他表中,外键允许为空。
应用程序不允许包含可能冲突的并行事务。
这是跟踪文件的头:
Deadlock graph:
---------Blocker(s)-------- ---------Waiter(s)---------
Resource Name process session holds waits process session holds waits
TX-134b0012-3201376f 65 185 X 33 392 S
TX-13495007-50f092d1 33 392 X 65 185 S
session 185: DID 0001-0012-04533045 session 392: DID 0001-0023-03401G5A
session 392: DID 0001-0023-03401G5A session 185: DID 0001-0012-04533045
Rows waited on:
Session 588: no row
Session 497: no row
在将键作为外键引用的表中插入空值会导致某种表扫描(不这么认为)吗?批量插入/更新可能会导致索引的更大分支被锁定吗?也许 T1 得到了树的一些左分支,而 T2 得到了右分支,现在 T1 想要在右分支中插入/更新一个值,但右分支仍然被 T2 锁定,T" 然后从左侧请求一些东西? 我不知道Oracle 中是否以及如何实现多粒度锁定,但如果有人能排除这一点,那就太好了。
即使事务在逻辑上是 100% 分离的,Oracle 是否有可能允许死锁?
我可以寻找什么?访问索引有问题吗?
PS:已设置读取已提交。
Oracle 中具有逻辑不相交事务的死锁通常涉及未索引的外键:
Oracle 中的锁在行级别进行管理。并发的不相交事务不应相互干扰。未索引的外键是一个例外,因为它可能导致完整的 TABLE LOCK。
您应该在死锁的跟踪文件中获取 SQL,这应该可以帮助您缩小对锁定负责的表/外键。一旦您知道哪个表受死锁影响,请确保对该表的所有外键引用都已正确索引。如果您的示例中的 EG
T2.t1_id
指向T1.t1_id
.或者,您可以使用上面链接中的 Tom Kyte 脚本来确定您是否有任何未索引的外键。
如果您被锁定在插入上,这通常意味着您正在尝试为一组唯一的列插入具有相同值的行,例如: