AWR报告能查到慢查询,但以聚合统计形式呈现而非原始日志;通过“SQL ordered by Elapsed Time”等章节定位高耗时SQL,再关联dba_hist_sqltext获取语句,结合执行计划分析根因。
oracle 没有像 mysql 那样直接写入磁盘的“慢查询日志文件”,所谓“看慢查询日志”,本质是查 v$sql、dba_hist_sqlstat 这类内存或历史性能视图,或者生成 awr 报告来定位高耗时 sql。
AWR 报告里真能查到慢查询吗?
能,但不是“日志”形式,而是聚合统计结果。AWR(Automatic Workload Repository)每小时默认采样一次,把 SQL 执行耗时、执行次数、逻辑读等指标存进 dba_hist_sqlstat。所以 AWR 报告中的 “SQL ordered by Elapsed Time” 或 “SQL ordered by CPU Time” 章节,就是你找慢查询最可靠的入口。
关键点:
- AWR 不记录原始 SQL 文本的完整日志,只保留
sql_id和摘要统计;要看到具体语句,得关联dba_hist_sqltext视图 - 必须有
SELECT_CATALOG_ROLE或DBA权限才能访问 AWR 相关视图和生成报告 - 默认只保留 8 天 AWR 快照(可通过
dba_hist_wr_control查),超期数据会被自动清理
怎么生成带慢 SQL 的 AWR 报告?
用 Oracle 自带的 @?/rdbms/admin/awrrpt.sql 脚本(在 SQL*Plus 或 SQL Developer 中运行),交互式选择起止快照 ID、实例号、报告类型(文本 or HTML)即可。生成后重点看这两块:
- “SQL ordered by Elapsed Time”:按总耗时排序,适合发现单次执行极慢的 SQL(比如 >5s)
- “SQL ordered by Executions”:按执行频次排序,适合发现高频低效 SQL(比如每秒执行上百次,平均 100ms,积少成多拖垮系统)
注意:Elapsed Time 是微秒单位,报告里已自动换算成秒;若某条 SQL 的 Executions 为 0,说明它没被正常解析执行过,可能是硬解析失败或被 cancel 掉了。
为什么查 v$sql 有时比 AWR 更快?
因为 v$sql 是共享池里的实时缓存,刚执行完的慢 SQL 可能还没落到 AWR 里(下个快照才收录)。紧急排查时,优先跑这个:
SELECT sql_id, sql_text, elapsed_time/1000000 AS elapsed_s, executions,
buffer_gets, disk_reads, cpu_time/1000000 AS cpu_s
FROM v$sql
WHERE elapsed_time/1000000 > 2 AND executions > 0
ORDER BY elapsed_time DESC
FETCH FIRST 20 ROWS ONLY;
但要注意:
-
v$sql只保留当前还在共享池里的 SQL,被老化淘汰或刷新后就没了 - 如果 SQL 含绑定变量,
sql_text可能被截断(尤其超 1000 字符),要用sql_fulltext字段补全 - 某些短生命周期会话(如应用连接池复用)可能让
executions统计不准,需结合last_active_time判断是否活跃
查到慢 SQL 后,下一步必须做执行计划分析
光知道哪条 SQL 慢没用,得知道它为什么慢。用 sql_id 查执行计划才是关键动作:
- 查最近一次执行的计划(从共享池):
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('abc123xyz')); - 查历史某次执行的计划(需指定快照 ID):
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR('abc123xyz', NULL, NULL, 'ALL'));
重点关注三处:
-
Operation出现TABLE ACCESS FULL且Rows很大 → 极大概率缺索引或索引失效 -
Index列为NULL→ 没走索引,哪怕表上有索引,也可能因隐式转换、函数包裹、统计信息过期导致 -
Cost值异常高(比如几十万),而实际返回行数很少 → 优化器估算严重失准,先收集统计信息再试
AWR 报告本身不提供执行计划,必须手动补这一步。很多人卡在这儿,以为报告里写了 SQL 就等于问题定位完了——其实那只是起点。











