<p>查 gv$active_session_history 必须用动态时间窗口如 SAMPLE_TIME > SYSDATE - INTERVAL '5' MINUTE,RAC 环境不可用 v$;需联合 session_state 与 event 分析等待分布突变,并结合 dba_hist_active_sess_history 和 v$sql 的 child_number、绑定变量定位根因。</p>

查 gv$active_session_history 时必须用动态时间窗口,别写死时间字符串
ASH 内存只保留约 1 小时(高负载下可能更短),写死时间如 '2026-09-17 20:00:00' 极易漏样:时区偏差、NLS 设置、采样非连续(每秒仅 1–10 次)都会导致关键样本被跳过。正确做法是用 SAMPLE_TIME > SYSDATE - INTERVAL '5' MINUTE 覆盖最近 5 分钟,不受会话时区影响。RAC 环境必须用 gv$active_session_history,否则只看到当前节点,而慢 SQL 可能卡在 node2 上。
对比“当前异常”和“历史正常”的等待分布,重点看 event + session_state 组合
单看某次 ASH 查询容易误判。真正有用的是横向对比:同一 sql_id 在不同时段的等待构成是否突变。例如:
- 当前窗口(异常期):
session_state = 'WAITING'且event IN ('enq: TX - row lock contention', 'db file sequential read')占比超 70% - 历史窗口(正常期):
session_state = 'ON CPU'占比 85%,event几乎为空
这种组合变化说明不是 SQL 本身逻辑变慢,而是执行环境恶化了——比如锁争用或 I/O 延迟。别只统计 event,一定要和 session_state 联合过滤,否则 log file sync 高但 session_state = 'ON CPU' 就可能是假信号。
用 dba_hist_active_sess_history 补全历史,但注意采样粒度差异
v$active_session_history 是内存视图,实时但短暂;dba_hist_active_sess_history 来自 AWR 快照,保留数天但采样间隔更粗(默认 10 秒)。查历史时必须意识到:它可能漏掉秒级尖刺,但适合看趋势。例如对比两个时段:
SELECT event, COUNT(*) cnt
FROM dba_hist_active_sess_history
WHERE sql_id = 'cuw23huyg926x'
AND sample_time BETWEEN TO_TIMESTAMP('2026-09-16 01:12:00', 'YYYY-MM-DD HH24:MI:SS')
AND TO_TIMESTAMP('2026-09-16 01:14:00', 'YYYY-MM-DD HH24:MI:SS')
GROUP BY event
ORDER BY cnt DESC;若发现 enq: US - contention 在历史窗口中几乎为 0,而当前窗口暴增,则基本锁定 undo 段争用;若 db file scattered read 同步飙升,再结合 v$iostat_file 中 AVG_READ_TIME 突增,就指向存储层问题。
别只盯 sql_id,child_number 和绑定变量值才是波动根源
同个 sql_id 可能对应多个子游标(child_number),执行计划完全不同。ASH 不记录 child_number,但 v$sql 和 dba_hist_sqlstat 有。如果当前慢,先查:
SELECT sql_id, child_number, plan_hash_value, executions, elapsed_time/executions avg_etime FROM v$sql WHERE sql_id = 'cuw23huyg926x' ORDER BY last_active_time DESC;
再用 dbms_xplan.display_cursor('cuw23huyg926x', <child_number>, 'outline +peeked_binds') 看真实计划和绑定值。常见陷阱是:一个 :b1 值触发索引扫描(快),另一个值触发全表扫描(慢),而 ASH 里只显示同一个 sql_id,看不出区别。


















