查ash必须加时间窗和session_state='waiting'双过滤,实操需满足sample_time > sysdate - 5/1440且session_state = 'waiting',再叠加event like 'enq: tx%'等条件,漏任一结果不可信。

查ASH必须加时间窗和session_state='WAITING'双过滤
不加这两个条件,结果基本不可信。批处理阻塞业务的典型场景是事务未提交、锁未释放,但ASH里存的是快照,不是实时状态。只筛blocking_session IS NOT NULL,可能捞出8分钟前就已回滚的“僵尸会话”;不设时间窗,v$active_session_history会扫全内存buffer(默认约1小时),轻则卡住查询,重则因权限不足报ORA-00942: table or view does not exist。
实操必须同时满足:SAMPLE_TIME > SYSDATE - 5/1440(最近5分钟)且session_state = 'WAITING',再叠加event LIKE 'enq: TX%'或event = 'library cache lock'。漏任一条件,看到的blocking_session = 456可能只是残留快照,不是当前真正在持锁的会话。
RAC环境下必须用final_blocking_session+final_blocking_instance
在RAC中,blocking_session只指向本节点的中间阻塞者,真正持锁的会话可能在另一个实例上。比如A→B→C级联阻塞,你kill了B,C还在等A持有的锁——因为A在实例2,而你只查了实例1的v$active_session_history。
正确做法:
- 必须查gv$active_session_history,并带上final_blocking_session和final_blocking_instance
- 用SELECT instance_number FROM v$instance确认该final_blocking_instance是否真实存在
- 若final_blocking_session为0或NULL,说明它是根阻塞源——大概率就是那个没提交的批处理会话
批处理SQL的ASH特征:sql_id高频+event集中+current_obj#稳定
批处理任务往往固定操作某张核心表(如ORDER_HEADER),ASH中会表现出三个强信号:
- 同一sql_id在连续几秒内反复出现在多个session_id样本里
- 等待事件集中在enq: TX - row lock contention或enq: TM - contention
- CURRENT_OBJ#指向同一个对象ID(可用SELECT object_name FROM dba_objects WHERE object_id = 12345反查)
若该sql_id对应的是UPDATE /*+ PARALLEL */ WHERE batch_id = ?这类语句,基本可锁定是批处理未控制并发粒度或未分页提交导致长事务持锁。注意:不要只看SQL文本,要结合sql_plan_hash_value判断是否执行计划突变引发性能退化。
还原阻塞链不能靠CONNECT BY,得用sample_id递减追踪
ASH是滚动内存表,每秒一条记录,SAMPLE_ID严格递增。用CONNECT BY PRIOR blocking_session = session_id会强行把不同时刻的会话拼在一起——比如把上午9:45的会话A和下午3:20的会话B错误关联,得出虚假阻塞路径。
真实阻塞路径得聚焦同一会话在连续时刻的行为:
- 先定位到某个高频率sql_id和event
- 按session_id分组,按SAMPLE_ID DESC排序,观察该会话在最近几秒内的blocking_session、event、sql_id是否持续变化
- 若发现某会话从ON CPU突然转为WAITING且blocking_session非空,那它大概率就是被阻塞的起点
批处理阻塞问题最易被忽略的点,是以为查到blocking_session就等于找到根因——但在RAC下它常是中间节点,在单实例下它又可能是已断开连接的残留快照。真正可靠的线索,永远是final_blocking_session + SAMPLE_ID连续性 + CURRENT_OBJ#一致性这三者的交叉验证。











