ASH报告为空通常因v$active_session_history未采集数据,主因是STATISTICS_LEVEL设为BASIC、_ash_sampling_interval调大、实例刚启动或处于QUIESCE状态;需检查参数及最近5分钟ASH记录。
ASH 报告没数据?先确认 v$active_session_history 是否真在采集
很多 dba 执行 @?/rdbms/admin/ashrpt.sql 后发现报告空或只有几条记录,第一反应是脚本坏了——其实大概率是底层没采到数据。oracle 默认每秒采样一次活跃会话,但这个行为依赖 statistics_level 必须设为 all 或 typical(basic 会彻底禁用 ash)。另外,_ash_sampling_interval 隐含参数被调大、实例刚启动还没积累足够样本、或者数据库处于 quiesce 状态,都会导致 v$active_session_history 行数极少。
实操建议:
- 查当前设置:
SELECT name, value FROM v$parameter WHERE name = 'statistics_level'; - 确认最近 5 分钟有没有 ASH 记录:
SELECT COUNT(*) FROM v$active_session_history WHERE sample_time > SYSDATE - 5/1440; - 别依赖
DBA_HIST_ACTIVE_SESS_HISTORY查“实时”问题——那是 AWR 快照汇总表,延迟至少 10 分钟
@ashrpt.sql 脚本跑不起来?注意它不接受时间范围参数,只走交互式流程
很多人想直接写成命令行一键生成:sqlplus / as sysdba @ashrpt.sql 2024-06-01/10:00 2024-06-01/10:15,结果报错或输出乱码。因为 @ashrpt.sql 是 Oracle 提供的交互式报告脚本,内部调用的是 awr_report_text 包,它不解析命令行参数,所有时间、实例号、报告类型都靠 SQL*Plus 的 ACCEPT 交互输入。强行传参只会让脚本卡在第一个提示符上,后续全错。
实操建议:
- 用
sqlplus / as sysdba @?/rdbms/admin/ashrpt.sql进入交互后,按提示依次输入:报告类型(text/html)、实例号(默认 1)、起止时间(格式必须是DD-MON-YYYY HH24:MI,比如01-JUN-2024 10:00) - 如果要自动化,改用 PL/SQL 调用
DBMS_WORKLOAD_REPOSITORY.ASH_REPORT_TEXT函数,传入l_start_time和l_end_timetimestamp 类型变量 - HTML 报告里点击“Top SQL with Top Events”展开后,注意看
SQL_ID列是否可点——不可点说明该 SQL 没进共享池或已被老化出内存,不能直接跳转执行计划
从 ASH 数据看出“伪高负载”:WAIT_CLASS = 'Idle' 的会话别当真
打开 ASH 报告,看到 DB CPU 占比低、Idle 占比奇高(比如 95%),就以为系统很空闲?不一定。Oracle 把 SQL*Net message from client、PL/SQL lock timer、jobq slave wait 这些统统归到 Idle 类,但它们背后可能是应用端长连接空等、定时任务堆积、或 PL/SQL 循环里写了 DBMS_LOCK.SLEEP。这类等待不消耗 CPU,却把会话占着不放,导致并发连接数虚高、连接池打满。
实操建议:
- 查真实非空闲等待:
SELECT event, wait_class, COUNT(*) FROM v$active_session_history WHERE wait_class != 'Idle' AND sample_time > SYSDATE - 1/1440 GROUP BY event, wait_class ORDER BY 3 DESC; - 重点关注
wait_class = 'Application'下的enq: TX - row lock contention,这往往意味着业务有未提交事务锁行,不是数据库慢,是应用逻辑卡住了 - ASH 中
session_state = 'WAITING'且event为空,说明会话正在执行 CPU 密集型操作(比如大排序、哈希连接),此时看sql_id对应的cpu_time增长速率比看等待事件更准
为什么 ASH 里找不到你刚执行的慢 SQL?sql_id 不等于执行中就能捕获
执行一条跑了 2 分钟的 SELECT /*+ FULL(t) */ COUNT(*) FROM big_table t;,立刻去查 v$active_session_history,却发现没有这条 sql_id 的记录。这不是 bug,是 ASH 的采样机制决定的:它只捕获“活跃”会话,而“活跃”定义为 session_state = 'ON CPU' 或 'WAITING'。如果 SQL 执行中大量时间花在客户端网络传输、应用层解析、或 SQL*Net 回传结果集(尤其是大结果集分批 fetch),这段时间 session_state 是 'INACTIVE',ASH 就不会记。
实操建议:
- 确认 SQL 是否真在运行中:
SELECT sql_id, status, state, event FROM v$session WHERE sql_id = 'your_sql_id';—— 如果status = 'INACTIVE',ASH 就不会出现它 - 对于结果集大的查询,
FETCH阶段不计入 ASH,但可以看v$sql的elapsed_time和fetches比值,若 fetches 多但每次 fetch_time 很短,说明瓶颈在客户端消费速度 - 想抓完整生命周期,得用
SQL Trace(ALTER SESSION SET EVENTS '10046 trace name context forever, level 8';),ASH 只负责“谁在忙”,不负责“谁在传”
ASH 是个快照,不是录像。它告诉你“在某个毫秒,谁在干啥”,但不保证覆盖整段执行过程——尤其当操作跨多个非活跃状态时,中间那段就丢了。这点最容易被当成数据缺失,其实是设计如此。


















