查不到十分钟前的ash数据,因v$active_session_history是内存视图,保留时间不固定(约1小时但受负载影响),高并发下可能5分钟前数据已被覆盖;应先查min(sample_time)确认实际可用范围,再决定用v$ash或dba_hist_active_sess_history。
查不到十分钟前的ash数据?先确认采样是否还在内存里
v$active_session_history 是内存视图,只保留最近约 1 小时(具体取决于负载)的采样,不是固定 60 分钟。高并发下缓冲区被快速覆盖,可能连 5 分钟前的数据都已丢失。别硬等 sysdate - 10/1440,先查实际可用时间范围:
- 运行
SELECT MIN(sample_time), MAX(sample_time) FROM v$active_session_history;看当前内存里最早能回溯到几点 - 如果
MIN(sample_time)比你想要的时间还晚,说明数据已被覆盖,得切到磁盘历史表dba_hist_active_sess_history -
dba_hist_active_sess_history默认每小时刷一次,但采样间隔是 10 秒而非 1 秒,细节会变粗——比如锁等待链可能断掉一环
用 sample_time 过滤必须带时区且精度足够
直接写 sample_time > SYSDATE - 10/1440 看似合理,但容易漏掉关键秒级采样。Oracle 的 sample_time 是 timestamp 类型,包含微秒,而 SYSDATE 是 date 类型,隐式转换会丢精度。
- 正确写法:
sample_time >= SYSTIMESTAMP - INTERVAL '10' MINUTE(推荐),或sample_time >= TO_TIMESTAMP_TZ('2026-06-24 06:50:00', 'YYYY-MM-DD HH24:MI:SS') - 避免用
TRUNC(SYSDATE)或TO_DATE,它们会截断到秒甚至更粗 - 如果查
dba_hist_active_sess_history,注意它按快照时间归档,sample_time实际是四舍五入到最近 10 秒的,所以“最后十分钟”可能对应多个快照 ID(snap_id),需联合DBA_HIST_SNAPSHOT查边界
还原故障现场不能只看 event,要抓 session_state + blocking_session 链
单纯过滤 event = 'enq: TX - row lock contention' 只能抓到等待方,但死锁或长事务阻塞的持有者可能早已释放锁、状态变成 ON CPU 或 WAITING,却仍留在采样里。
- 必须同时捕获两类行:
session_state = 'WAITING'(正在等)和blocking_session IS NOT NULL(正在被等) - 重点看
blocking_session和blocking_session_serial#是否成对非空;单独blocking_session为 NULL 时不可信 - 若怀疑循环等待(如 A→B→A),同一
sample_time下找sid与blocking_session互指的组合,并交叉比对p1/p2(TX 锁中 undo segment# 和 slot# 对调即大概率互锁)
从 ASH 关联 SQL 执行计划要防 plan_hash_value 漂移
查出问题 sql_id 后,想看当时真实执行路径,不能直接查 DBA_HIST_SQL_PLAN 并按 sql_id 过滤——同一 sql_id 在不同时间可能有多个 plan_hash_value,而历史视图默认只存最新一个。
- 务必带上时间条件:
timestamp BETWEEN ... AND ...,且该时间范围要和 ASH 查询的sample_time匹配 - 加
dbid和instance_number条件,RAC 环境下漏掉这个会跨实例拿错计划 - 如果
DBA_HIST_SQL_PLAN里没找到对应记录,说明该 SQL 当时未被自动捕获进 AWR(比如硬解析失败、执行时间太短),只能退回到v$sql_plan查当前缓存(但很可能已失效)
ASH 不是录像机,它是按秒抽样的快照集。还原“最后十分钟”,本质是拼凑一组时间邻近、状态互指、事件一致的碎片。最易忽略的不是语法,而是采样粒度与内存生命周期之间的 gap——你以为还在那儿的数据,其实早被新请求挤出去了。











