AWR报告不显示单次执行时间,必须下钻到DBA_HIST_ACTIVE_SESS_HISTORY或V$ACTIVE_SESSION_HISTORY,通过SAMPLE_TIME、time_waited(微秒)、session_state等字段定位偶发超时的毛刺执行,结合SQL_ID与plan_hash_value变化诊断执行计划退化。

AWR报告不显示单次执行时间,必须下钻到基表
AWR报告只提供平均值(elapsed_time / executions),根本看不到哪一次执行卡了60秒而其他99次都只要20ms。业务报“偶发超时”,问题就藏在这种毛刺里。直接翻报告里的“SQL ordered by Elapsed Time”没用——它排序依据是总耗时,不是单次峰值。
-
DBA_HIST_SQLSTAT也不行:它同样只存聚合值,没有单次快照粒度 - 真正能抓到单次最慢执行的,只有
DBA_HIST_ACTIVE_SESS_HISTORY(ASH)和V$ACTIVE_SESSION_HISTORY - 关键字段是
TIME_MODEL和SESSION_STATE,但更直接的是用ELAPSED_TIME在历史会话中反推
用ASH查单次最慢执行:核心SQL要带SAMPLE_TIME过滤
直接查 V$ACTIVE_SESSION_HISTORY 是最准的,因为它是1秒采样一次的真实运行痕迹。重点不是看“谁总耗时高”,而是找“谁在某次采样中连续被捕捉到ON CPU或WAITING状态超过N秒”。
- 执行下面语句前,先确认当前有没有长事务:
SELECT sid, serial#, sql_id, event, seconds_in_wait FROM v$session WHERE status = 'ACTIVE' AND seconds_in_wait > 60 - 再查单次最慢记录:
SELECT sql_id, sql_plan_hash_value, sample_time, session_state, event, time_waited, sql_text FROM v$active_session_history a JOIN v$sqlarea s ON a.sql_id = s.sql_id WHERE session_state = 'ON CPU' AND time_waited > 5000000 -- 超过5秒的单次等待/执行片段 ORDER BY time_waited DESC FETCH FIRST 5 ROWS ONLY; - 注意:
time_waited单位是微秒,5000000 = 5秒;它反映的是该采样点上该会话在该事件上已累积等待/执行的时间,不是整条SQL生命周期
为什么不能只靠v$sql的elapsed_time排序
v$sql 里 elapsed_time 是所有执行的累计值,除以 executions 得到平均值。如果一条SQL执行了1万次,其中1次跑了120秒、其余9999次都是20ms,v$sql 显示的平均值才约21.1ms,根本排不进Top 100。
- 这种SQL在“SQL ordered by Elapsed Time”里会被高频短SQL淹没
-
v$sql的last_active_time和first_load_time只能告诉你它最近什么时候跑过,不能定位具体哪次慢 - 真正要抓毛刺,得结合
ASH的时间戳 +sql_plan_hash_value+session_id三者关联,才能还原出完整单次执行上下文
容易被忽略的两个细节:SAMPLE_TIME精度和plan_hash_value漂移
ASH采样不是精确计时器,而是“每秒拍一张快照”。如果某次SQL执行刚好跨采样点(比如第1.9秒开始、第6.1秒结束),它可能被拆成4~5个采样记录,time_waited 值分散在不同行里。这时候光看最大单值会漏掉真实瓶颈。
- 查到可疑
sql_id后,一定要用DBA_HIST_SQL_PLAN对比不同快照里的plan_hash_value—— 执行计划突变(如从索引扫变成全表扫)才是单次暴涨的主因 - 别跳过
DBA_HIST_SQLSTAT中同一sql_id在不同snap_id下的buffer_gets和disk_reads变化:突然飙升说明物理I/O激增,大概率是执行计划退化导致 - 如果
sql_plan_hash_value没变但单次耗时暴涨,优先查绑定变量窥探(peeked)、统计信息陈旧或临时表数据倾斜


















