ash查活跃会话的实时等待事件、资源争用和高负载sql,不查非活跃会话、完整执行计划、精确总耗时、绑定变量值及已老化出共享池的sql。
ash视图查什么,不查什么
ASH(Active Session History)记录的是每秒采样的活跃会话快照,不是全量SQL日志。它适合回答“此刻哪些SQL正在拖慢系统”“谁在争抢CPU/IO”,但无法还原完整执行计划或精确统计某条SQL的总耗时——因为采样有丢失、聚合有延迟。
-
V$ACTIVE_SESSION_HISTORY保留默认约1小时(受内存和_ash_size隐含参数影响),历史数据会滚动覆盖 - 不记录非活跃会话(比如SQL执行完等待客户端读取结果的空闲状态)
- 某些短于1秒的SQL可能被完全漏采,尤其在高并发下
所以别指望用ASH查“昨天下午3点那条慢查询的完整绑定变量值”,它压根没存。
定位高负载SQL的三个关键过滤维度
直接查V$ACTIVE_SESSION_HISTORY容易被噪声淹没,必须组合以下三类条件缩小范围:
- 按等待事件:重点关注
event= 'db file sequential read'(单块读)、'log file sync'(提交等待)、'enq: TX - row lock contention'(行锁)等真实瓶颈信号,避开SQL*Net message from client这类假热点 - 按时间窗口:用
sample_time过滤最近10–30分钟,避免跨采样周期导致统计失真 - 按对象或模块:结合
current_obj#(关联DBA_OBJECTS查表名)或module字段(应用常设此值),快速锁定业务模块
示例语句:
SELECT sql_id, COUNT(*) cnt, ROUND(AVG(time_waited),2) avg_wait_ms FROM v$active_session_history WHERE sample_time > SYSDATE - 1/24 AND event LIKE 'db file%' AND current_obj# IN (SELECT object_id FROM dba_objects WHERE object_name = 'ORDER_DETAIL') GROUP BY sql_id ORDER BY cnt DESC;
为什么sql_id对不上V$SQL里的记录
常见现象:ASH里看到高频sql_id,但查V$SQL发现EXECUTIONS为0、LAST_ACTIVE_TIME很旧,甚至查不到该sql_id。
- 原因1:SQL已老化出共享池,
V$SQL只保留当前缓存中的SQL,而ASH采样是独立内存区,不依赖共享池存活 - 原因2:SQL使用了绑定变量窥探(bind peeking)且存在硬解析,不同绑定值生成多个子游标,ASH里看到的是实际执行的子游标
sql_id,但主游标可能已被刷出 - 原因3:某些PL/SQL匿名块或动态SQL未被持久化进
V$SQL(尤其autotrace或DBMS_SQL构造的语句)
此时应转向DBA_HIST_SQLTEXT(需开启AWR)或用sql_id查V$SQL_PLAN(若还在内存中),而非死守V$SQL。
ASH分析后下一步必须做的验证动作
拿到可疑sql_id只是起点,跳过这步验证极易误判:
- 用
DBMS_XPLAN.DISPLAY_ASH(12c+)或DBMS_XPLAN.DISPLAY_CURSOR(sql_id, child_number)看真实执行计划,确认是否走了索引、有没有全表扫描或嵌套循环爆炸 - 对比
V$SESSION_LONGOPS中同一sql_id的进度,判断是单次长操作(如大排序)还是反复短等待(如索引分裂) - 检查该SQL涉及的表是否近期做过统计信息收集:
LAST_ANALYZED在DBA_TABLES里是否过期,过期统计信息会让优化器选错路径,ASH只会显示结果,不解释原因
没有执行计划和统计信息状态交叉验证的ASH分析,就像只看体温计读数就开药方——数字没错,但病因可能完全不对。










