最能定位卡顿源头的是SESSION_ID、SQL_ID、EVENT三字段组合:SESSION_ID标识会话,SQL_ID对应执行语句,EVENT揭示等待类型(如enq: TX为行锁、db file sequential read为单块读),需配合SQL_EXEC_START/SQL_EXEC_ID避免混用不同执行实例。

ASH视图里哪些字段最能定位卡顿源头
直接看 V$ACTIVE_SESSION_HISTORY(或 DBA_HIST_ACTIVE_SESS_HISTORY 归档表)里三个关键字段:SESSION_ID、SQL_ID、EVENT。它们组合起来能快速锁定“谁、在跑哪条 SQL、卡在哪类等待上”。比如 EVENT 是 db file sequential read,大概率是索引单块读慢;如果是 enq: TX - row lock contention,基本就是事务行锁冲突。
注意:SESSION_ID 和 SQL_ID 要和 SQL_EXEC_START、SQL_EXEC_ID 配合查,避免把不同执行实例的样本混在一起。ASH 每秒采样一次,但只保留活动会话,空闲或已断开的不会记录。
怎么查过去 5 分钟内最耗时的等待事件
用这个查询快速聚焦瓶颈:
SELECT EVENT, COUNT(*) AS WAITS, ROUND(COUNT(*) * 10, 2) AS SECONDS FROM V$ACTIVE_SESSION_HISTORY WHERE SAMPLE_TIME >= SYSDATE - 5/1440 GROUP BY EVENT ORDER BY WAITS DESC FETCH FIRST 10 ROWS ONLY;
说明:SAMPLE_TIME >= SYSDATE - 5/1440 表示最近 5 分钟(1440 是一天的分钟数);COUNT(*) * 10 是粗略换算成秒(因采样间隔约 1 秒,但实际有抖动,不能当精确耗时用)。
- 别用
DBA_HIST_ACTIVE_SESS_HISTORY查实时卡顿——它延迟至少 1 小时,只适合事后复盘 - 如果
EVENT大量是ON CPU,说明不是等待,而是 SQL 真的在猛算,该看执行计划和逻辑读 - 注意
SESSION_STATE = 'WAITING'的才计入EVENT,ON CPU或UNKNOWN需单独过滤
如何关联 SQL_ID 找出具体执行的语句和绑定变量
拿到可疑 SQL_ID 后,优先查 V$SQL 获取文本和统计:
SELECT SQL_TEXT, EXECUTIONS, BUFFER_GETS, ELAPSED_TIME/1000000 ELAPSED_SEC FROM V$SQL WHERE SQL_ID = 'abc123xyz';
如果语句含绑定变量且怀疑是变量窥探导致计划劣化,再查 V$SQL_BIND_CAPTURE:
SELECT NAME, DATATYPE_STRING, VALUE_STRING FROM V$SQL_BIND_CAPTURE WHERE SQL_ID = 'abc123xyz' AND LAST_CAPTURED > SYSDATE - 1/24;
注意:V$SQL_BIND_CAPTURE 默认只捕获前 1000 个唯一值,且不保证每次执行都抓——它按采样策略来,所以看到空结果不等于没绑参。
-
V$SQL中的SQL_TEXT可能被截断(默认 1000 字符),长语句要用DBMS_LOB.SUBSTR或查DBA_HIST_SQLTEXT - 如果
SQL_ID在V$SQL里查不到,说明已老化出库缓存,得从DBA_HIST_SQLTEXT或 AWR 报告里捞
为什么按 SESSION_ID + SAMPLE_TIME 排序反而容易误判
因为 ASH 样本不是严格按时间顺序插入的,SAMPLE_TIME 有毫秒级偏移,且同一秒内多个会话可能被打包进同一批采样。直接 ORDER BY SESSION_ID, SAMPLE_TIME 看“会话行为流”,常出现时间跳变或重复。
更稳妥的方式是:先按 SQL_ID 或 EVENT 聚合,再用 MIN(SAMPLE_TIME) 和 MAX(SAMPLE_TIME) 算持续区间,辅以 COUNT(*) 判断热度。
- 不要依赖单条 ASH 记录还原完整事务链——它没有事务 ID(
XID)字段,SESSION_ID+SQL_ID+SQL_EXEC_ID才勉强对应一次执行 - 如果业务卡顿发生在凌晨批处理时段,记得检查
DBA_HIST_ACTIVE_SESS_HISTORY是否启用了快照,否则可能压根没归档那段数据
真实卡顿分析中,最大的盲区不是不会写 SQL,而是忘了 ASH 只反映“当时正在做什么”,不解释“为什么这么做”——比如一个 latch: shared pool 等待,背后可能是硬解析风暴,也可能是频繁的 DBMS_METADATA 调用,得结合应用调用栈和 AWR 的 Parse CPU/Elapsed 对比才能闭环。


















