v$active_session_history视图不含USERNAME字段,仅含USER_ID,直接SELECT USERNAME会报ORA-00904;必须JOIN dba_users映射用户名,且该视图内存数据仅保留约1小时,无法跨天回溯。
直接查 v$active_session_history 按 user_id 聚合就能定位到具体用户,但必须手动关联 dba_users 才能拿到用户名;ash 内存数据默认只保留约 1 小时,不能跨天回溯。
为什么查不到 USERNAME 字段就报 ORA-00904?
v$active_session_history 视图里压根没有 USERNAME 列,只有 USER_ID。常见错误是写 SELECT USERNAME, COUNT(*) FROM v$active_session_history GROUP BY USERNAME,结果直接报 ORA-00904: "USERNAME": invalid identifier——这是最常踩的第一个坑。
必须显式 JOIN dba_users 或用子查询把 user_id 映射成用户名:
-
dba_users是静态字典,只要用户没被删,关联就是可靠的 - 若只关心当前活跃用户,
dba_users够用;若需历史用户(如已删账号),得换dba_hist_active_sess_history+dba_hist_user,但后者需额外 license 且不常用
怎么写最小可行 SQL 统计 CPU 和等待资源?
下面这条语句能同时看出某用户在最近 30 分钟内占用了多少 CPU 时间、多少等待时间,以及主要等在什么事件上:
SELECT u.username,
COUNT(*) total_samples,
SUM(CASE WHEN ash.session_state = 'ON CPU' THEN 1 ELSE 0 END) cpu_samples,
SUM(CASE WHEN ash.session_state = 'WAITING' THEN 1 ELSE 0 END) wait_samples,
MAX(ash.event) KEEP (DENSE_RANK FIRST ORDER BY COUNT(*) DESC) OVER (PARTITION BY u.username) top_wait_event
FROM v$active_session_history ash
JOIN dba_users u ON ash.user_id = u.user_id
WHERE ash.sample_time > SYSDATE - 30/1440
GROUP BY u.username
ORDER BY cpu_samples + wait_samples DESC;
注意几个关键点:
-
SYSDATE - 30/1440表示 30 分钟前,比INTERVAL '30' MINUTE更兼容老版本(如 11gR2) -
COUNT(*)是总采样数,1 样本 ≈ 10ms,所以cpu_samples * 10是近似毫秒级 CPU 占用时长 -
MAX() KEEP (DENSE_RANK FIRST)是取每个用户出现次数最多的等待事件,避免按event分组后结果太散
想进一步定位到具体会话和 SQL,该加哪些字段?
光知道“用户 A 消耗多”不够,得定位到是哪个会话、跑哪条 SQL、来自哪个应用模块。这时要在 SELECT 和 GROUP BY 中加入:
-
SESSION_ID和SESSION_SERIAL#:组合唯一标识一次会话生命周期 -
SQL_ID和SQL_CHILD_NUMBER:同一sql_id可能对应多个执行计划,忽略child_number容易误判 -
MODULE和ACTION:反映应用层调用上下文,比如'JDBC Thin Client'或自定义模块名
例如加了这些字段后,就能快速识别出:“用户 HR 下的某个 Java 应用模块,通过子游标 2 执行了某条 sql_id,持续在 enq: TX - row lock contention 上等待”。
为什么不能用 DBA_HIST_ACTIVE_SESS_HISTORY 直接替代?
dba_hist_active_sess_history 看起来能跨天查,但它依赖 AWR 快照,默认每小时打一次,采样粒度粗(丢失大量细节),且首次快照生成有延迟(通常 OPEN 后 1 小时才开始)。真正要抓瞬时尖刺、会话级行为、SQL_ID 级分布,还是得靠内存中的 v$active_session_history。
容易被忽略的一点是:v$active_session_history 在 RAC 环境下必须用 gv$active_session_history,否则只看到当前实例的样本,可能漏掉其他节点上的高消耗用户。











