优先查v$active_session_history——它是内存中最近1小时每秒采样的高密度ASH数据,无需额外授权,适合实时等待链分析;超时则退用dba_hist_active_sess_history,并严格限定sample_time范围。

直接用 v$active_session_history 而不是 DBA_HIST_ACTIVE_SESS_HISTORY
DBA_HIST_ACTIVE_SESS_HISTORY 是 AWR 快照数据,采样间隔默认 60 秒,且需授权 + 手动保留策略控制。对“特定事务”的实时等待链分析来说,它容易漏掉关键样本(比如只捕获到阻塞末端,没抓到源头)。必须优先查 v$active_session_history —— 它是内存中最近 1 小时的高密度采样(默认每秒 1 次),且无需额外权限(SELECT_CATALOG_ROLE 或 SELECT ANY DICTIONARY 即可)。
- 确保目标时段在最近 60 分钟内,否则
v$active_session_history已被覆盖 - 若需跨小时分析,才退而求其次用
DBA_HIST_ACTIVE_SESS_HISTORY,但要加WHERE sample_time BETWEEN ...严格限定范围,避免全表扫描 - 不要依赖
/<em>+ materialize </em>/提示——在 19c 中该提示对v$视图无效,反而可能干扰优化器选择
CONNECT BY 链必须从 blocking_session IS NOT NULL 的会话开始
等待链不是从任意会话发起的,而是从“正在等待”的会话反向追溯持有锁的源头。错误写法如 START WITH event = 'enq: TX - row lock contention' 只能捕获等待事件本身,无法展开完整链条。
- 正确起点是:
START WITH blocking_session IS NOT NULL AND blocking_session <> session_id - 必须补上
AND blocking_session_serial# = session_serial#的等值约束,否则可能把不同会话误连成链(Oracle 19c 对 serial# 匹配更严格) - 加
NOCYCLE是必须的,尤其在存在会话自阻塞(如递归调用死循环)时,否则报ORA-01436: CONNECT BY loop in user data
路径拼接建议用 session_id || ',' || sql_id || ',' || event 而非纯 sql_id
只拼 sql_id 会导致不同会话执行相同 SQL 时路径混淆;只拼 session_id 又丢失上下文。真实排查中,你既要看谁在等,也要看它在等什么、执行哪条语句。
- 示例片段:
sys_connect_by_path(session_id || ',' || NVL(sql_id, 'NULL') || ',' || event, ' → ') -
NVL(sql_id, 'NULL')防止空值导致整条路径为NULL - 使用中文顿号或箭头符号(如
→)比短横线->更易读,且不会被 SQL*Plus 截断
过滤 isleaf = 1 后必须 GROUP BY 并按 COUNT(*) DESC 排序
isleaf = 1 表示该路径末端没有下游等待者,即“阻塞终点”——这才是你要定位的根因会话。但一个根因可能引发多条分支等待,不聚合就看不出影响面。
- 必须
GROUP BY path,否则count(*)无意义 -
RATIO_TO_REPORT(COUNT(*)) OVER ()能快速识别占比超 20% 的主干链,比单纯看数量更有效 - 切忌省略
ORDER BY COUNT(*) DESC:排第一的路径往往就是业务高峰期卡住审批流的那个事务
实际执行时,最常被忽略的是时间精度。用 TO_DATE('2026-09-17 14:30:00', 'YYYY-MM-DD HH24:MI:SS') 会丢失秒级精度,应统一用 TO_TIMESTAMP,否则可能漏掉关键 1~2 秒的锁争用窗口。


















