如果阻塞有多层,把源头会话kill掉不一定会使所有的会话被释放,因为被锁定的资源不一样:
A->B A锁定了B要获取的行1
C->A C锁定了A要获取的行2
C->A->B 如果kill掉C会话,行2被释放,那么A不会再被阻塞,但是B仍然会被阻塞,因为B要的资源行1仍然被A持有,除非A不再持有B需要的资源。
针对这种情况,不是kill了源头就释放了所有被阻塞的会话,还要看下一层是否继续持有资源。
可以把C称为链条头,同时C是A的阻塞源头,A是B的阻塞源头。
具体示例:
![]()
|
WITH w1 AS (SELECT (CASE WHEN connect_by_isleaf = 0 THEN 'alter system kill session ''' || s.sid || ',' || s.serial# || ',@' || s.inst_id || ''' immediate;' ELSE NULL END) AS kill_ddl, --生成阻塞会话的kill语句 (CASE WHEN connect_by_root(s.sid || '@' || s.inst_id) = s.sid || '@' || s.inst_id THEN 'Y' ELSE NULL END) AS block_head, --阻塞头 --connect_by_root(s.sid) top_sid, lpad(' ', (LEVEL - 1) * 2, ' ') || substr(sys_connect_by_path(s.sid || '@' || s.inst_id, '->'), 3) block_chain, s.inst_id, s.sid, s.serial#, s.blocking_instance AS block_inst_id, s.blocking_session AS block_sid, --被这个会话阻塞,可以理解成父节点 s.final_blocking_instance AS final_block_inst_id, s.final_blocking_session AS final_block_sid, s.status, s.logon_time, s.sql_id, s.event, s.seconds_in_wait wait_time_s FROM gv$session s START WITH EXISTS (SELECT 1 FROM gv$session s2 WHERE s.inst_id = s2.inst_id AND s.sid = s2.blocking_session) --获取有阻塞的节点 CONNECT BY PRIOR s.inst_id = s.blocking_instance AND PRIOR s.sid = s.blocking_session) SELECT * FROM w1;
|