查指定用户最近慢SQL应优先用v$active_session_history(每秒采样),限定sample_time>SYSDATE-INTERVAL'30'MINUTE、session_type='FOREGROUND'、user_id匹配,并按sql_id统计样本数判断“慢”,RAC环境须用gv$并指定inst_id。

查指定用户最近的慢SQL,优先用 v$active_session_history 而非 AWR 视图
因为你要的是“慢SQL”,不是“历史快照汇总”——DBA_HIST_ACTIVE_SESS_HISTORY 每小时只存一次快照,采样稀疏,容易漏掉真实执行卡顿的秒级样本。而 v$active_session_history 是每秒采样,只要用户那条 SQL 在采样瞬间处于 ON CPU 或 WAITING 状态,就会被捕获。关键是要限定时间窗口、排除干扰会话。
- 必须加
sample_time > SYSDATE - INTERVAL '30' MINUTE(或更窄),ASH 内存默认只保留约 1 小时,高负载下可能更短 - 必须加
session_type = 'FOREGROUND',否则会混入后台进程(如CKPT、DBW0)的样本 - 过滤用户要靠
user_id字段,不是username;先查dba_users拿到目标用户的user_id,再 JOIN 或子查询关联 - 别直接
WHERE username = 'xxx'——v$active_session_history不存用户名,只存user_id,硬写会全表扫且无结果
怎么定义“慢”?按 ASH 样本密度而非执行耗时
ASH 里没有 elapsed_time 字段,没法像 v$sql 那样直接排序“执行时间最长”。所谓“慢SQL”,在 ASH 中体现为:同一 sql_id 在短时间窗口内被高频采样到非空闲状态。样本数越多,说明它越可能拖住资源。
- 用
COUNT(*)统计每个sql_id的样本数,是判断“慢”的最可靠指标 - 加
session_state = 'ON CPU'可聚焦真正消耗 CPU 的 SQL;加wait_class IN ('User I/O', 'Application', 'Concurrency')可定位等锁、等磁盘、等 latch 的 SQL - 避免只看
event单一值——比如enq: TX - row lock contention出现 5 次,比db file sequential read出现 50 次更紧急,但样本总数仍是基础 - 示例语句中不要用
BETWEEN,改用sample_time >= TO_TIMESTAMP('2026-09-30 17:45:00', 'YYYY-MM-DD HH24:MI:SS'),防止边界截断
sql_text 查不到?立刻切到 DBA_HIST_SQLTEXT 或 v$sql 补全
v$active_session_history 只存 sql_id,不存文本。你 JOIN v$sql 发现 sql_text 为空,不是 SQL 不存在,而是它已老化出共享池——尤其在 19c 默认启用 INMEMORY 和频繁硬解析的场景下很常见。
- 先试
SELECT sql_text FROM v$sql WHERE sql_id = 'xxx',有就直接用 - 没结果就查
DBA_HIST_SQLTEXT:SELECT sql_text FROM dba_hist_sqltext WHERE sql_id = 'xxx' ORDER BY piece,注意长 SQL 要按piece排序拼接 - 若两者都空,说明该 SQL 既没进过共享池,也没进过 AWR 快照(可能执行极快、或被采样错过),此时只能靠
program、module、action字段反推上下文 - 别在 ASH 查询里直接
LEFT JOIN v$sql——v$sql可能正在被清理,JOIN 会导致结果不稳定甚至报错
RAC 环境下必须用 gv$active_session_history 并显式指定 INST_ID
单实例查 v$ 没问题,但 RAC 下 v$active_session_history 只返回当前实例的数据。如果你查不到某条用户 SQL,大概率它跑在别的节点上,而你连的只是其中一个实例。
- 统一改用
gv$active_session_history,并加WHERE inst_id = &inst_id或GROUP BY inst_id分析各节点分布 - 别依赖
gv$自动聚合——不同节点的sample_time可能有毫秒级偏差,直接UNION ALL后排序比用gv$更可控 - 如果目标用户跨实例执行(如应用连接池轮询),需合并所有节点结果再按
sql_id统计总样本数,否则低估“慢”的程度 -
gv$视图访问需要SELECT_CATALOG_ROLE,权限不足会报ORA-00942,提前确认账号权限
实际执行中最容易被忽略的是时间精度和用户映射方式:ASH 的 sample_time 是 TIMESTAMP 类型,用字符串比较会隐式转换失败;而 user_id 是数字,不能和用户名字符串混用。这两个点一错,整条查询就查不到数据,却很难意识到是条件写错了。











