查指定SQL的历史等待事件必须用DBA_HIST_ACTIVE_SESS_HISTORY而非v$active_session_history,因其持久化存储AWR快照(默认每小时1次、保留8天),而v$视图仅保留约1小时内存样本;需显式转时间戳、过滤INST_ID(RAC)、结合session_state与event判断真实执行状态,并注意child_number差异。

查指定 SQL 的历史等待事件,必须用 DBA_HIST_ACTIVE_SESS_HISTORY 而非 v$active_session_history
因为 v$active_session_history 只存最近约 1 小时的内存样本,而你提到“历史某时刻”,说明已超出该窗口。直接查 v$ 视图大概率返回空——不是语句写错,是数据早就被循环覆盖了。
正确路径是走 AWR 持久化视图:DBA_HIST_ACTIVE_SESS_HISTORY。它按快照粒度(默认每小时 1 次,可调)把 ASH 样本刷入磁盘,保留时间由 AWR_RETENTION_POLICY 控制(通常 8 天)。但要注意:它的采样频率是每 10 秒一次,比内存版稀疏得多。
- 先确认目标时刻是否落在已有快照范围内:
SELECT snap_id, begin_interval_time FROM dba_hist_snapshot ORDER BY begin_interval_time DESC FETCH FIRST 5 ROWS ONLY - 若目标时间在两个快照之间(比如你想查 2026-09-15 14:23:17),
DBA_HIST_ACTIVE_SESS_HISTORY可能没这个精确时间点的样本——它只记录快照周期内的离散采样点 - 别用
BETWEEN包死时间范围;用sample_time >= TO_TIMESTAMP('...', '...') AND sample_time 更稳妥,避免边界截断
sql_id 匹配后查不到 SQL_TEXT?优先查 DBA_HIST_SQLTEXT
DBA_HIST_ACTIVE_SESS_HISTORY 只存 sql_id,不存文本。如果执行 SELECT sql_text FROM v$sql WHERE sql_id = 'xxx' 返回空,不是 SQL 不存在,而是它早已老化出共享池。
这时必须转向历史文本表:DBA_HIST_SQLTEXT。它从 AWR 快照中提取 SQL 文本,只要该 SQL 在对应快照周期内执行过,且被采集到,就能查到。
- 查文本:
SELECT sql_text FROM dba_hist_sqltext WHERE sql_id = 'your_sql_id' - 若仍为空,说明该 SQL 在任何 AWR 快照周期内都没被完整捕获(可能执行太快、或恰好错过快照窗口);此时只能退回到
v$active_session_history查最近 1 小时内是否有残留样本 -
DBA_HIST_SQLTEXT中的sql_text可能被截断(默认 1000 字符),长 SQL 需用PIECE排序拼接:SELECT sql_text FROM dba_hist_sqltext WHERE sql_id = 'xxx' ORDER BY piece
时间精度陷阱:用 TO_TIMESTAMP,别用字符串硬编码
写 WHERE sample_time > '2026-09-15 14:23:17' 是高危操作——会触发隐式类型转换,依赖 NLS_DATE_FORMAT 和会话时区,极易漏数据或报错。
必须显式转为时间戳,并指定格式:
sample_time >= TO_TIMESTAMP('2026-09-15 14:23:17', 'YYYY-MM-DD HH24:MI:SS')- RAC 环境下务必加
INST_ID过滤,否则可能跨节点混查,导致时间对不上 - 如果目标时刻很短(如 30 秒内),建议扩大窗口到 2 分钟再聚合,避免因 10 秒采样间隔错过关键点
查到事件但看不懂?重点看 session_state + event 组合
单看 event 列容易误判。比如 enq: TX - row lock contention 出现多次,不代表 SQL 本身慢,可能是被别的事务堵住。
真正反映“执行中”的只有两种状态组合:
-
session_state = 'ON CPU'且event IS NULL→ 真正在 CPU 上跑这条 SQL -
session_state = 'WAITING'且event是非空闲事件(如db file sequential read、log file sync)→ 等待 I/O 或日志写入 - 若
session_state = 'WAITING'但event是SQL*Net message from client,说明应用端没发下一条请求,和数据库无关
最易忽略的是:同个 sql_id 在不同 child_number 下可能对应完全不同计划,而 DBA_HIST_ACTIVE_SESS_HISTORY 不带 child_number。若怀疑计划变更,得额外查 DBA_HIST_SQL_PLAN 关联 plan_hash_value。


















