执行路径应先盯住operation和options列:重点检查table access full、index fast full scan或高cardinality的nested loops,以及storage、by index rowid batched等提示;index full scan无order by且表大时多为优化器误判。
怎么看执行路径:先盯住 operation 和 options 列
awr sql 报告里的执行路径不是靠“读完全部计划”来判断的,而是快速定位高成本、低效访问方式。重点看 operation 列是否出现 table access full、index fast full scan 或 nested loops 配合驱动表 cardinality 过高(比如 >10 万);再看 options 列有没有 storage(说明用了 exadata 智能扫描)、by index rowid batched(批量回表,较优)等关键提示。
特别注意:如果 Operation 是 INDEX FULL SCAN 却没带 ORDER BY,而目标表有几十万行,大概率是优化器误判——它把单块读当便宜,忽略了多块读的吞吐优势,这在 19c 中常由 optimizer_index_cost_adj 偏离实际 I/O 特性导致。
为什么 AWR 报告里同一个 SQL_ID 有多个执行计划
AWR 报告按快照聚合,只要 SQL 在不同时间点走了不同执行路径,就会并列展示。这不是异常,而是真实负载波动的体现。常见触发场景包括:
- 统计信息夜间自动刷新后,优化器重估成本,放弃索引改走全表扫描
- 绑定变量窥探(
bind peeking)遇上数据倾斜,第一次用'A'值生成计划,后续传'Z'却复用旧计划 -
adaptive plans在运行时动态切换分支(如从NESTED LOOPS切到HASH JOIN),AWR 会分别记录两种终态
别急着删旧计划——先比对各计划的 Elapsed Time Per Exec 和 Buffer Gets Per Exec,确认哪个真慢、哪个只是偶尔跑偏。
如何用 dbms_xplan.display_awr 精准拉出某次慢执行的计划
AWR 报告只给摘要,要查具体某次慢执行的完整计划,必须用 dbms_xplan.display_awr,且需带上 plan_hash_value 和 dbid(否则默认查当前库):
SELECT * FROM TABLE(dbms_xplan.display_awr( '3jm7s0g3w2px0', 1000005031, -- 注意这是 plan_hash_value,不是 SQL_ID NULL, 'ADVANCED +PEEKED_BINDS' ));
关键点:
-
plan_hash_value必须从 AWR 报告 “SQL ordered by Elapsed Time” 表里抄,不能手算或猜 - 加
+PEEKED_BINDS才能看到当时实际代入的绑定值,这对判断谓词是否失效至关重要 - 如果查不到结果,大概率是该计划已被老化出 AWR(默认保留 8 天),此时得切回
display_cursor查最近一次硬解析的计划
执行路径正常但还是慢?检查 I/O 类型和等待事件是否匹配
执行计划写的是 INDEX RANGE SCAN,不代表真快——得看它背后干了什么。打开 AWR 报告的 “SQL ordered by Reads” 页面,找对应 SQL 的 Physical Reads 和等待事件:
- 若
db file sequential read占比高,且计划是索引访问,说明回表频繁或索引选择性差,可能需要覆盖索引 - 若
db file scattered read高,但计划没写FULL,可能是隐式转换导致索引失效,或谓词未下推到分区剪枝层 - 若
read by other session明显,说明热点块争用,跟执行路径无关,得看 buffer busy waits 分布
最易被忽略的一点:19c 默认启用 in-memory column store,如果表已加载进内存,但执行计划仍显示磁盘访问路径,说明 IM 列存未生效(比如没设 INMEMORY 属性或查询含不支持函数),这时计划“看起来合理”,实则完全绕过了加速层。











