必须用gv$active_session_history实时查夜间定时任务阻塞,因其内存仅保留约1小时,AWR报告滞后且采样稀疏,无法捕获凌晨2–4点的瞬时阻塞;须限定SAMPLE_TIME > SYSDATE - INTERVAL '5' MINUTE,结合program LIKE '%J%'、final_blocking_session及event精准定位根因。

夜间定时任务阻塞必须用 gv$active_session_history 实时查,不能等第二天看 AWR 报告——ASH 内存只保留约 1 小时,而定时任务常在凌晨 2–4 点执行,早上登录时样本早已刷出内存。
查 gv$active_session_history 锁定“黄金 5 分钟”窗口
定时任务一卡,立刻连上数据库执行查询,时间窗必须动态、窄、跨实例:
-
SAMPLE_TIME > SYSDATE - INTERVAL '5' MINUTE是底线,写死时间字符串(如'2026-10-26 02:30:00')大概率漏掉关键采样点 - RAC 环境下必须用
gv$active_session_history,否则只看到当前节点的等待链,而真正持锁的 job slave(J000或J001)可能在 node2 - 加
AND program LIKE '%J%'或AND program LIKE '%M%'快速聚焦 job 相关会话,常见值为oracle@host (J000)(job slave)、oracle@host (M000)(mmon slave)
识别是否真由定时任务引发阻塞
定时任务本身不发 SQL,但它的 PL/SQL 调用路径会留下强特征:
-
sql_id IS NULL且plsql_entry_object_id IS NOT NULL→ 纯 PL/SQL 层执行(如循环处理、调用DBMS_LOCK.SLEEP、JSON 解析),不是 SQL 慢 -
event = 'PL/SQL lock timer'且session_state = 'WAITING'→ 极大概率是匿名块或过程里写了DBMS_LOCK.SLEEP(10)这类休眠,但没控制调用频次 -
CURRENT_OBJ#高度集中于某张日志表(如MLOG$_ORDERS)或物化视图基表 → 指向 MV 刷新任务;再查v$session的action字段,若含REFRESH或SNAPSHOT可确认
区分“任务慢”和“任务阻塞别人”
同一个定时任务可能既自己卡住,又成为别人阻塞源。关键看 final_blocking_session 和等待事件组合:
- 若
final_blocking_session IS NOT NULL且event = 'enq: TM - contention'→ 它正在 truncate 或 alter 表,锁了 DDL,下游所有访问该表的业务 SQL 全被堵住 - 若
final_blocking_session IS NOT NULL且event = 'library cache lock'→ 它刚执行过 DDL(如CREATE OR REPLACE PROCEDURE),其他会话正等它释放库缓存锁 - 若
final_blocking_session = 0或NULL,但program是J000,且sql_id IS NULL→ 它就是根阻塞源,90% 是未提交的大事务(如UPDATE /*+ PARALLEL */ ...后忘了COMMIT)
为什么 DBA_HIST_ACTIVE_SESS_HISTORY 基本没用
这张历史表对夜间定时任务排查帮助极小:
- 默认每 10 秒批量刷一次,而定时任务阻塞常发生在秒级(比如
DBMS_SCHEDULERjob 启动后 2 秒就卡死),采样点极易错过 - 字段
blocking_session在 19c 以前版本不稳定,部分行为空或为 0,导致阻塞链断裂 - 一旦 job 自动失败或被 kill,后续采样中
blocking_session被清空,历史表只剩“单边等待”,看不出环 - 真正能用它的地方,只是事后验证:用
gv$active_session_history找到的精确sample_time(如2026-10-26 02:44:37),再去历史表里查同一秒附近是否有连续采样佐证
最易被忽略的是:定时任务阻塞往往不是代码逻辑问题,而是资源配额或依赖未就绪——比如 job 设置了 resource_plan = 'DAYTIME_PLAN',但夜间该 plan 未激活;或依赖的外部表链接(DBLINK)在凌晨因防火墙策略中断,PL/SQL 里没设超时直接 hang 住。











