v$active_session_history是唯一能直接定位“谁在抢资源”的实时证据源,它每秒采样活动会话,不依赖快照、不经过聚合,天然适合抓取瞬时争用,如CPU打满、行锁争用或RAC节点间gc等待。
v$active_session_history 是唯一能直接定位“谁在抢资源”的实时证据源。它不依赖快照、不经过聚合,每秒采样活动会话(cpu 或非空闲等待),天然适合抓取瞬时争用——比如某个 sql 突然把 cpu 打满、某张表被大量 enq: tx - row lock contention 卡住、或 rac 节点间频繁 gc cr block busy。
为什么不用 AWR 或 dba_hist_active_sess_history 查抢占?
AWR 快照默认 60 分钟一次,dba_hist_active_sess_history 是 AWR 的副产品,采样粒度实际是每 10 秒一次(且只保留活动会话)。当资源抢占发生在几秒内(如短连接风暴、批量作业启动瞬间),AWR 根本捕不到峰值细节。v$active_session_history 才是内存里真实滚动的“秒级录像带”,只要没被覆盖(ASH buffer 通常保 30–60 分钟),就能回溯到具体哪一秒、哪个会话、哪条 SQL、哪个对象在锁死资源。
查 CPU 抢占:过滤 session_state = 'ON CPU' 并按 SQL 和会话聚合
高 CPU 不一定等于坏 SQL,但持续 ON CPU 的会话大概率是根因。别只看 sql_id,要结合 program、module 和 client_identifier 判断来源。
SELECT sql_id, program, module, COUNT(*) cnt FROM v$active_session_history WHERE session_state = 'ON CPU' AND sample_time > SYSDATE - 1/24 GROUP BY sql_id, program, module ORDER BY cnt DESC FETCH FIRST 5 ROWS ONLY;- 如果
program是oracle@host (J000),说明是 job 进程;如果是jdbc thin client,就得查应用端线程池配置 - 注意:
sql_id为0000000000000000表示未解析或硬解析中,此时重点看sql_opname和event
查锁与阻塞链:用 blocking_session 和 blocking_session_serial# 追源头
资源抢占常表现为“一堆会话卡在同一个事件上”,比如 enq: TM - contention 或 latch: shared pool。单看等待事件只能知道“被卡”,必须顺藤摸瓜找到第一个持锁者。
- 先查当前最热阻塞点:
SELECT event, COUNT(*) cnt FROM v$active_session_history WHERE blocking_session IS NOT NULL AND sample_time > SYSDATE - 1/48 GROUP BY event ORDER BY cnt DESC FETCH FIRST 3 ROWS ONLY; - 再定位根因会话:
SELECT blocking_session, blocking_session_serial#, sql_id, event, sample_time FROM v$active_session_history WHERE blocking_session IS NOT NULL AND sample_time > SYSDATE - 1/48 AND ROWNUM - 关键点:
blocking_session字段只在采样时刻存在阻塞关系时才非空,不是持续状态;所以必须用时间窗口聚合,不能只查单行
查 RAC 跨节点干扰:聚焦 gc 类事件 + inst_id 对比
RAC 环境下,资源抢占往往藏在跨实例通信里。gc current block 2-way 高本身不异常,但如果集中在某一个 instance(比如 node1 持有块,node2/node3 频繁请求),就是典型的数据倾斜。
- 快速识别热点实例:
SELECT inst_id, event, COUNT(*) cnt FROM gv$active_session_history WHERE event LIKE 'gc%' AND sample_time > SYSDATE - 1/24 GROUP BY inst_id, event ORDER BY cnt DESC; - 对比各节点平均活跃会话:
SELECT inst_id, COUNT(*)/120 avg_active FROM gv$active_session_history WHERE sample_time > SYSDATE - 1/24 GROUP BY inst_id;(120 是 2 分钟内的采样数) - 容易忽略的坑:
gv$视图需在所有实例上执行,若只连一个节点,inst_id永远显示当前实例号,无法横向比较
真实问题往往不在单条 SQL 或单个事件里,而在多个维度交叉处:比如某个 module = 'ETL_BATCH' 的会话,在 node2 上持续 ON CPU,同时 node1 上大量会话在等它的 gc cr block 2-way —— 这才是完整的抢占链。别急着 kill session,先确认这个 ETL 是否该跑在 node2,或者是否该加 partition 减少跨节点访问。


















