Lunar 拥有超过十年的 ORACLE SUPPORT 从业经验,曾经服务于ORACLE ACS部门,现就职于 ORACLE Sales Consultant 部门,负责的产品主要是 Exadata,Golden Gate,Database 等。
编辑手记:此文通过分场景环环紧扣的测试,深入剖析了enq: TM – contention等待事件的原理,今日拣选与大家共享。
结论:当外键无索引时
1,对子表的insert操作所在的事务没有完成前,对于父表的DML操作(INSERT/UPDATE/DELETE)都会因为不能获得对子表的TM锁而出现enq: TM – contention。
2,在1的基础上,如果又有了对子表的insert,那么这个对子表的insert同样被阻塞,等待事件也是 enq: TM – contention。
3,对父表的insert会阻塞对父表的delete。同样的道理,此时对父表的insert也阻塞对父表的update pk操作。
当没有索引的时候
测试1, 在子表发生 Insert,然后在父表上有update操作
Session 1: 对子表进行insert,不commit时:
这是,我们看到,该回话在主表(1062788 DEPT)和子表(1062790 EMP)上都分别持有了 exclusive lock(LMODE=3)锁
同时,该回话还持有一个tx锁(在子表 emp上)
另开一个会话,观察锁:
Session 2 : 然后,我们在父表做DML操作update:
Session 3: 检查锁的变化
这是我们看到,Session 2 在子表(1062790 EMP)上请求LMODE=4,并在主表(1062788 DEPT)上持有等待:enq: TM – contention
这是很清晰,有blocker了,也就是Session 1(SID 321),此时该回话正在对子表(1062790 EMP)进行插入操作.
换句话说,当外键无索引时,对子表的insert操作,会造成对父表的更新操作的阻塞。
Session 4 更新父表:
这是我们看到,session 4(sid 116)遵循了跟session 220同样的所规律
这是我们在Session 1中执行commit,在Session 3中观察:
可以看到Session 2和Session 4都完成了update:
Session 2:
这里我们看到,当外键无索引时,对子表的insert操作,会造成对父表的更新操作的阻塞,该阻塞直到子表的insert事务结束,才自动释放。
测试2, 在子表发生 Insert,然后在父表上有update操作,然后再有一个会话对子表做insert
重复上面的操作,不对session 1进行commit时,再开一个窗口(Session 5)对子表做insert
这是我们看到,对于子表的insert语句被阻塞了。
在Session 3中观察:
这里我们看到:
1,当外键无索引时,对子表的insert操作,会造成对父表的更新操作的阻塞,该阻塞直到子表的insert事务结束,才自动释放。
2,如果对子表有insert操作,在这个insert所在事务没有commit之前,有对父表的update,那么接下来的对子表的inser会被阻塞
测试3:
在测试2的场景上,将session 2和session 4中的对父表的update执行Ctrl+C,然后分别改为INSERT 和delete 父表(dept)的操作,观察一下
Session 4:
Session 5 随之自动解锁,并报了正常的违反约束的错误:
在session 2中执行delete 父表的操作:
注意:
1,delete父表的操作被阻塞,依然是正在请求以LMODE=4的模式对子表(1062790 EMP)的TM锁
2,这里的sid 222中为非活动会话,当该回话执行了commit或者rollback后,这个Insert的“SQL*Net message from client”等待就会消失了。
测试4: 在测试3的场景上,继续session 4中的对父表做insert 的操作,观察一下
Session 4:
这里我们看到,虽然Session 4执行的是对父表的insert,session 2执行的是对父表的 delete,他们的表现跟update的表现都是相同的。也就是说,对于子表的insert操作所在的事务没有完成前,对于父表的DML操作(INSERT/UPDATE/DELETE)都会因为不能获得对子表的TM锁而出现enq: TM – contention
测试5: 在测试4的基础上,我们在Session 1对做commit,完成对子表的insert操作,然后观察其他session:
Session 1:
Session 4:对父表的insert插入操作随着session 1的commit 自动解锁:
Session 2(SID 220):对父表的delete操作依然是hang的状态:
也就是说,这里我们看到了,对父表的insert,阻塞了对父表的delete