ASH的时间模型基于采样频次估算时间占比,非精确毫秒计时;核心按session_state(ON CPU/WAITING/NULL)分组分析,误差约±20%,需结合v$sql等视图交叉验证。

ASH的time model数据不是直接可加总的时间值
ASH里没有叫“time_model”或“elapsed_time”的列,它不提供毫秒级精确耗时,而是用采样频次来估算时间占比。每个样本代表该会话在那一秒处于某种状态(ON CPU、WAITING等),所以“10个ON CPU样本” ≈ 该SQL在过去N秒内占用了约10秒CPU时间——前提是采样没丢、没被覆盖。
常见误解是把COUNT(*)当真实耗时,但实际误差可能达±20%:采样是概率性每秒1次,并非严格准时;环形缓冲区满后老样本被覆盖;RAC环境下不同实例采样时间点存在微小偏移。
- 别用
SUM(wait_time)——v$active_session_history中wait_time绝大多数为0,Oracle只在等待结束瞬间记录一次,不是累计值 - 真正可用的只有
session_state和event组合,靠频次反推资源占用强度 - 若需毫秒级时间度量,必须切到
v$session_event或v$sesstat实时视图,ASH只适合“哪类消耗最重”的快速归因
按session_state分组才是time model分析的起点
Oracle time model的核心分类就三个:ON CPU、WAITING、空(即NULL,表示空闲或未采样)。ASH把所有活动会话都映射进这三类,所以第一步永远是按session_state过滤再聚合。
例如查某会话最近5分钟时间分布:
SELECT session_state, COUNT(*) samples FROM v$active_session_history WHERE session_id = 1234 AND sample_time > SYSDATE - INTERVAL '5' MINUTE GROUP BY session_state;
结果中ON CPU占60%、WAITING占35%、NULL占5%,就能立刻判断:这不是I/O瓶颈,而是CPU密集型操作+少量锁等待。
-
session_state = 'WAITING'必须配合wait_class看——Concurrency类等待(如enq: TX%)比System I/O类更紧急 -
session_state IS NULL不等于“没干活”,可能是采样间隙,也可能是短于1秒的瞬时操作被跳过 - RAC环境务必用
gv$active_session_history,否则单节点查询会漏掉跨实例等待的样本
用sample_time窗口卡不准,time model分析就失效
ASH内存缓冲区默认保留约1小时数据,但高负载下可能压缩到20分钟以内。你查SAMPLE_TIME > SYSDATE - INTERVAL '30' MINUTE,结果为空,不代表没发生问题——很可能数据已被覆盖。
实操中必须动态计算时间窗,且留出余量:
- 查最近5分钟:用
SAMPLE_TIME > SYSDATE - INTERVAL '5' MINUTE,别写死'2026-08-27 05:55:00'——NLS_DATE_FORMAT偏差会导致全空 - 若目标事件发生在已知时间点(如06:02:17),建议放宽到
SAMPLE_TIME BETWEEN SYSDATE - INTERVAL '10' MINUTE AND SYSDATE,避免因采样抖动错过 - 确认当前缓冲区剩余容量:
SELECT COUNT(*) FROM v$active_session_history,低于5000条说明数据正在高速滚动,需立刻抓取
不要试图从ASH还原单次SQL执行的完整时间线
一个UPDATE语句执行3.2秒,在ASH里可能只留下2~3个样本:1个ON CPU(解析/执行)、1个WAITING(enq: TX%)、1个ON CPU(清理)。它无法告诉你“第1.7秒发生了什么”,也不记录SQL开始/结束时间戳。
想定位长事务或慢SQL,必须交叉验证:
- 先用ASH圈出高样本SQL_ID → 查
v$sql的elapsed_time和executions算平均耗时 - 再查
v$transaction确认是否持有大量used_ublk,排除undo膨胀干扰 - 最后用
DBA_HIST_SQLSTAT比对历史执行计划变化,判断是否统计信息陈旧导致计划劣化
单独依赖ASH做time model分析,就像只用行车记录仪帧数估算车速——能知道快慢趋势,但没法替代码表读数。


















