要查指定SQL ID的等待事件,应查询dba_hist_active_sess_history或v$active_session_history,加sql_id、时间范围和session_state='WAITING'条件;若查不到,可能是SQL执行过快未被1秒采样捕获。
如何从ASH中查出指定SQL ID的等待事件?
直接查 v$active_session_history(或 dba_hist_active_sess_history)是最可靠的方式,但必须注意时间范围和采样精度。ash每秒采样一次活跃会话,所以它只能反映“正在执行且未完成”的sql在那一秒的状态——如果sql执行很快(比如毫秒级),大概率不会被捕获。
实操建议:
- 优先用
dba_hist_active_sess_history(AWR快照中的ASH),它保留7–30天(取决于AWR保留策略),适合回溯历史问题;实时诊断则用v$active_session_history,但注意它只保留约1小时(默认) - WHERE条件必须包含
sql_id = 'xxx',并加上时间过滤,例如sample_time > SYSDATE - 1/24(最近1小时) - 别漏掉
session_state = 'WAITING',否则会混入大量ON CPU的行,干扰等待分析 - 关键字段:
event(等待事件名)、p1text/p2text(参数含义)、wait_time(0表示正在等,>0表示刚结束等待)
为什么查不到某个SQL ID的ASH记录?
不是所有执行都会进ASH——只有满足“活跃 + 非空闲 + 被采样到”三个条件才会留下痕迹。常见漏采场景:
- SQL执行太快:比如单次执行
- SQL被硬解析后立即结束:解析阶段不计入SQL执行统计,ASH里可能只看到
library cache lock或parse time elapsed等解析相关等待,但没对应sql_id - 会话处于空闲状态(
session_state = 'INACTIVE')或执行的是PL/SQL匿名块(无独立sql_id) - AWR未启用或快照间隔太长(如1小时一拍),导致
dba_hist_active_sess_history中缺失中间时段数据
如何关联等待事件与具体资源争用?
光看 event 名称不够,得结合参数(p1, p2, p3)定位底层对象。Oracle官方文档对每个事件的参数有明确定义,但实践中更高效的做法是用视图映射:
- 对
enq: TX类事件,查p1(锁类型+模式)转成十六进制,再用chr(bitand(p1,-16777216)/16777216)||chr(bitand(p1,16711680)/65536)解出锁名称(如TX、TM) - 对
db file sequential read,p1是文件号,p2是块号,可联查dba_data_files和dba_extents定位具体段 - 对
latch: shared pool,p2是latch地址,可用select * from v$latch_children where addr = hextoraw('...')查争用详情
别依赖 event 字面意思做判断——log file sync 高频出现,未必是IO慢,可能是应用提交太频繁;cursor: pin S wait on X 往往指向绑定变量未重用或硬解析风暴。
用ASH分析时最容易忽略的两个细节
一是采样偏差:ASH按会话采样,不是按SQL采样。一个SQL并发100个会话,只要其中1个在某秒处于WAITING状态,就记1条;但100次执行只耗时1ms,也可能一条记录都没有。
二是SQL ID复用:同一文本的SQL在不同优化器环境(如绑定变量窥探开启与否、统计信息新旧)下会产生不同 sql_id。如果只盯一个ID,可能错过实际执行计划差异带来的等待迁移。
真要定位根因,得把ASH结果和 v$sql 的 executions、elapsed_time、buffer_gets,以及 v$sql_plan 的实际执行计划串起来看——等待只是表象,执行路径和资源消耗才是关键。


















