v$active_session_history不能直接反映整体等待分布,必须过滤session_state='WAITING'、排除空闲事件并分组聚合,才能准确统计各等待事件的占比与时长。

v$active_session_history 能直接告诉你「谁在等、等什么、等多久、从哪来」,但不能直接回答「整体等待分布」——必须加条件过滤、分组聚合,否则查出来是杂乱样本。
查 v$active_session_history 前先确认采样是否有效
ASH 默认每秒采一个活动会话,但只记录 session_state = 'WAITING' 且非空闲事件的样本。如果查不到数据,不是没发生等待,而是:
• 实例刚启动不久,v$active_session_history 缓冲区还没填满(最小 1MB,通常需几分钟活跃后才有足够样本)
• 会话大部分时间在 CPU 上运行(session_state = 'ON CPU'),不属于「等待」范畴
• 等待事件本身属于空闲类(如 SQL*Net message to client、PL/SQL lock timer),ASH 明确不采集
• 查询时间范围太窄(比如只查最近 5 秒),而 ASH 采样是滚动覆盖的,老样本可能已被覆盖
按等待事件统计分布必须过滤 session_state 和空闲事件
直接 SELECT event, COUNT(*) FROM v$active_session_history GROUP BY event 会混入大量干扰项。正确做法是:
- 限定
session_state = 'WAITING',排除 CPU 运行态 - 排除空闲等待:
event NOT IN ('SQL*Net message to client', 'PL/SQL lock timer', 'pmon timer', 'rdbms ipc message') - 用
COUNT(*) * 10近似「秒级等待时间」(因 ASH 每秒采一次,每个样本代表约 1 秒) - 加
sample_time > SYSDATE - 1/24限制为最近 1 小时,避免跨周期数据稀疏
示例语句:
SELECT event, COUNT(*) * 10 AS wait_secs, ROUND(RATIO_TO_REPORT(COUNT(*)) OVER() * 100, 2) AS pct
FROM v$active_session_history
WHERE session_state = 'WAITING'
AND event NOT IN ('SQL*Net message to client', 'PL/SQL lock timer', 'pmon timer', 'rdbms ipc message')
AND sample_time > SYSDATE - 1/24
GROUP BY event
ORDER BY wait_secs DESC;
SQL*Net message from client 长等待几乎肯定不是数据库问题
这个事件排在 Top,平均 time_waited 超过 100000 微秒(即 100ms),基本可判定瓶颈不在 Oracle 内核:
• 客户端连接池配置过小,频繁建连断连,触发服务端 TCP TIME_WAIT 端口耗尽
• 中间网络设备(防火墙、负载均衡器)丢包或拦截健康检查探针
• 客户端应用未及时读取响应,socket 缓冲区塞满,服务端 send() 阻塞
• machine 字段显示同一客户端 IP 大量会话同时卡住,而其他 IP 正常 → 典型链路问题
此时不该调优 SQL 或加大 shared_pool,而应查:
• 客户端连接池最大连接数、超时设置、是否复用连接
• netstat -an | grep TIME_WAIT | wc -l 看服务端 TIME_WAIT 数量是否接近 net.ipv4.ip_local_port_range
• 抓包看是否有 TCP Retransmission 或 Dup ACK
区分硬解析和软解析要靠 in_hard_parse 和 in_parse
单纯看 library cache lock 或 cursor: pin S 等待,无法判断是不是解析引发的 —— 必须结合解析状态列:
• in_hard_parse = 'Y':正在做硬解析(语法检查、语义分析、生成执行计划)
• in_parse = 'Y' 且 in_hard_parse = 'N':软解析(仅校验共享池中是否存在可复用 cursor)
• 两者都为 'N':已解析完成,当前等待与解析无关
典型误判场景:
• 查到大量 cursor: pin S 等待,但 in_parse = 'N' → 实际是并发 DML 修改同一对象导致的 library cache mutex 争用,不是解析问题
• sql_id 为空,但 in_hard_parse = 'Y' → DDL 编译阶段尚未生成 sql_id,需结合 sql_opname(如 'CREATE'、'ALTER')定位
真实环境中,等待分布图只是起点。最常被忽略的是:ASH 统计的是「采样瞬间的状态」,不是持续时间的精确积分;一个持续 3 秒的等待,若刚好没被采到,就不会计入。所以单次查询结果偏低,要连续观察 3–5 分钟趋势,再交叉验证 v$session_wait 和操作系统工具(如 tcpdump、perf)。


















