ash是独立于awr的实时采样源,v$active_session_history每秒采样,dba_hist_active_sess_history为其归档,awr则为定时聚合统计;排查瞬时性能问题必须用ash。

ASH数据不是AWR的子集,而是独立采样源
很多人误以为ASH是AWR里“抽出来的一小部分”,其实完全相反:v$active_session_history 是内存中每秒采样的实时快照,dba_hist_active_sess_history 才是它的持久化归档;而AWR快照(dba_hist_snapshot)只是定时打包的聚合统计。两者时间对齐但逻辑隔离——你不能指望在AWR报告里“点开ASH详情”,必须单独查ASH视图或生成ASH报告。
关键区别在于:AWR告诉你“过去一小时谁平均占CPU多”,ASH告诉你“第37分22秒是谁正在吃满一个核”。排查瞬时CPU尖峰、短时锁争用、单条SQL突发高CPU,必须用ASH。
- 默认ASH内存保留约1小时(
V$ACTIVE_SESSION_HISTORY),历史归档保留8天(DBA_HIST_ACTIVE_SESS_HISTORY),但需注意:归档数据可能被压缩或采样降频,尤其在高负载时段 - 查不到最近1小时数据?先确认是否启用了ASH:检查
SELECT value FROM v$parameter WHERE name = 'statistics_level',值必须是ALL或TYPICAL(BASIC会禁用ASH) - 生产库若发现
DBA_HIST_ACTIVE_SESS_HISTORY为空,大概率是SYSAUX表空间满或_ash_disk_filter_ratio隐含参数被调得过高(不建议手动改)
直接查dba_hist_active_sess_history定位高CPU会话
别等报告生成,用SQL直击核心。目标很明确:找出指定时间段内,session_state = 'ON CPU' 且 sql_id 非空的记录,并按CPU消耗聚合。
示例(查今天14:00–15:00的CPU热点):
SELECT sql_id,
COUNT(*) as cpu_samples,
ROUND(COUNT(*) * 10, 2) as cpu_sec_estimated,
COUNT(DISTINCT session_id) as active_sessions
FROM dba_hist_active_sess_history
WHERE sample_time BETWEEN TIMESTAMP'2026-08-26 14:00:00'
AND TIMESTAMP'2026-08-26 15:00:00'
AND session_state = 'ON CPU'
AND sql_id IS NOT NULL
GROUP BY sql_id
ORDER BY cpu_samples DESC
FETCH FIRST 10 ROWS ONLY;
-
COUNT(*) * 10是估算依据:ASH每秒采样1次,但归档表默认每10秒存1条(即采样率≈0.1Hz),所以每个样本≈10秒CPU时间——这是最常被忽略的换算系数 - 结果里
cpu_sec_estimated超过你实例总CPU秒数(如4核×3600秒=14400秒),说明该SQL反复执行、或并行度高、或存在大量递归调用 - 如果
sql_id是0000000000000000或全为字母数字但查dba_hist_sqltext为空,大概率是PL/SQL匿名块、触发器、或硬解析失败的语句,需结合program和module字段判断来源
为什么sql_id 对应的SQL文本查不到?
v$sql 和 dba_hist_sqltext 都可能找不到对应文本,原因不同,处理方式也不同:
-
v$sql里没有 → SQL已被老化(aged out),必须查dba_hist_sqltext;但要注意:Oracle 11g+才支持sql_fulltext字段,10g只能看到前1000字符,容易误判谓词条件 -
dba_hist_sqltext里sql_text显示为/* SQL Analyze(123) */ SELECT ...→ 这是DBMS_SQLTUNE自动SQL分析任务生成的,不是业务SQL;此时要结合program = 'oracle@host (J000)'或module = 'DBMS_SCHEDULER'确认是否为维护作业 -
sql_id存在但sql_fulltext为空 → 可能是DDL(如CREATE INDEX)、密码重置、或审计语句,它们不走SQL引擎,ASH只记状态不记文本 - 查
dba_hist_sqltext慢?加条件WHERE sql_id = 'xxx' AND dbid = (SELECT dbid FROM v$database),避免跨数据库历史数据扫描
结合gv$px_session和gv$session看并行SQL的CPU分布
RAC或并行环境下,一条SQL的CPU可能分散在多个进程甚至多个节点,只看sql_id聚合会掩盖真相。比如sql_id = 'abc123xyz' 在ASH里显示CPU高,但实际是QC(Query Coordinator)串行部分卡住,而非PX Server并行部分。
- 先确认是否并行:查
SELECT * FROM gv$sql WHERE sql_id = 'abc123xyz' AND px_servers_executions > 0 - 再看分布:用
gv$px_session查该SQL各PX进程的CPU时间:SELECT qcsid, sid, server_group, server_set, degree FROM gv$px_session WHERE qcsid IN (SELECT sid FROM gv$session WHERE sql_id = 'abc123xyz') - 关键陷阱:ASH里
session_id记的是PX Server的SID,不是QC的SID;所以聚合时若没区分qcsid,会把QC的等待(如px qc wait for reply)和PX Server的真实CPU混在一起 - 真正要盯的是:QC所在会话的
event是否为ON CPU,且sql_id是否与PX Server一致——若不一致,说明QC在跑PL/SQL逻辑或排序,问题不在SQL本身
ASH分析最难的不是查SQL,而是分辨“谁真在干活”:后台进程(Jnnn)、调度作业(CJQn)、并行协调器(QC)、还是前台应用会话。同一个sql_id 在不同program下代表完全不同的风险等级。别跳过program和module字段,它们才是上下文锚点。











