从awr揪出执行路径长的sql,应重点分析buffer_gets_total/executions_total>100000且cpu_time_total/elapsed_time_total异常偏低、plan_hash_value频繁变动的语句,结合dba_tab_statistics和dba_tab_modifications验证统计信息陈旧性,并用dbms_xplan.display_awr+peeked_binds检查绑定值与直方图匹配度。
怎么从awr里揪出执行路径长的sql?
直接看 dba_hist_sqlstat 里的 elapsed_time_total 和 executions_total 不够——耗时高未必路径长,可能是i/o卡住或并发争用。真正反映执行路径复杂度的,是 buffer_gets_total 和 cpu_time_total 的比值异常偏高,再结合 plan_hash_value 变动频繁,基本可以锁定“路径膨胀”的嫌疑sql。
实操建议:
- 先筛出最近7天内
BUFFER_GETS_TOTAL / EXECUTIONS_TOTAL > 100000且CPU_TIME_TOTAL / ELAPSED_TIME_TOTAL 的SQL(说明大量时间花在逻辑读而非CPU计算,路径很可能绕弯) - 用
DBA_HIST_SQL_PLAN关联该SQL_ID,重点查OPERATION列含NESTED LOOPS或VIEW嵌套超过4层的行 - 注意
OTHER_XML字段里是否有dynamic_sampling或adaptive_plan标记——自适应计划切换失败常导致优化器选错驱动表,路径陡增
为什么PLAN_HASH_VALUE相同但实际执行路径不同?
PLAN_HASH_VALUE 只哈希了执行计划结构(操作符、连接顺序、访问路径),不包含绑定变量值、统计信息版本、动态采样结果等运行时因素。同一 SQL_ID 下,如果 DBA_HIST_SQLSTAT.PLAN_HASH_VALUE 没变,但 DBA_HIST_SQL_PLAN.OTHER_XML 里 is_adaptive 为 TRUE,且 adaptive_plan_status 是 FINAL,说明实际运行中发生了运行时计划调整,比如从 HASH JOIN 回退到 NESTED LOOPS,逻辑读会暴增。
排查要点:
- 查
DBA_HIST_SQL_PLAN中同一PLAN_HASH_VALUE下,OTHER_XML是否存在多个不同adaptive_plan_status记录 - 对比
DBA_HIST_SQLSTAT中相同SQL_ID不同快照的IO_WAIT_TIME_TOTAL和CLUSTER_WAIT_TIME_TOTAL,若后者突增,大概率是远程对象访问或物化视图刷新引发的隐式路径扩展 - 禁用自适应计划不是万能解法:设置
optimizer_adaptive_plans=FALSE后,需同步检查_optimizer_ds_dir_usage是否为FALSE,否则动态采样仍可能干扰基数估算
如何用AWR报告快速验证某SQL是否走了长路径?
生成单个SQL的AWR报告(awrrpti.sql)比翻表更直观。关键不是看“Elapsed Time”,而是盯住 “SQL ordered by Gets” 部分里的 Buffer Gets per Exec 和 “SQL Plan Monitoring Details” 里的 Actual Rows vs Starts 比值。
典型长路径信号:
-
Starts明显大于1(比如1000次),但Actual Rows却只有个位数 → 子操作被反复驱动,常见于未加过滤条件的外连接或视图展开失控 -
Buffer Gets per Exec> 500K 且计划中出现多层VIEW+UNION-ALL→ Oracle把视图合并后生成超长单表访问路径,尤其当基表有函数索引或虚拟列时易触发 - 报告底部 “Instance Activity Stats” 里
parse time elapsed占比异常高(>15%)→ 每次执行都在硬解析新计划,可能因绑定变量窥探失效导致优化器反复重估路径
定位后怎么确认是不是统计信息问题?
长路径八成和统计信息不准强相关,但不能只看 LAST_ANALYZED 时间。要查 DBA_TAB_STATISTICS 里的 STALE_STATS 和 NUM_ROWS 与当前 COUNT(*) 的偏差,更要看 DBA_TAB_COL_STATISTICS 中高频值(NUM_DISTINCT)和直方图类型(HISTOGRAM)是否匹配真实数据分布。
实操动作:
- 对疑似表执行
DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO,再查DBA_TAB_MODIFICATIONS,若INSERTS+UPDATES+DELETES > 0.1 * NUM_ROWS,说明变更量已超自动收集阈值,但统计信息没更新 - 用
DBMS_XPLAN.DISPLAY_AWR查历史执行计划时,加参数format=>'+PEEKED_BINDS',看绑定值是否落在直方图盲区(比如字段有严重倾斜,但直方图是FREQUENCY类型却漏掉了最大频次值) - 临时固定执行计划前,先用
DBMS_STATS.LOCK_TABLE_STATS锁住相关表,避免自动任务覆盖刚修正的统计信息
真正难的是区分“路径长”是优化器误判,还是业务逻辑本就该扫这么多数据。有时候 INDEX RANGE SCAN 看似高效,但配合 INLIST ITERATOR 走上万次循环,总逻辑读反而碾压全表扫描——这时候得看应用层能不能把 IN 列表拆成批量处理,而不是只盯着SQL改写。











