sql执行计划抖动主因是优化器因统计信息过期、绑定变量窥探偏差、分区/索引统计不全及隐式类型转换,导致不同时间生成不同执行路径。需定期更新统计信息、启用acs、校验数据类型一致性。

SQL执行计划抖动,本质是优化器在不同时间生成了不同的执行路径,导致性能忽高忽低。最常见诱因是统计信息变化和绑定变量/参数值差异,二者常交织作用,不能孤立看待。
统计信息过期或采样不准,引发计划“突变”
当表数据量增长显著(如日增百万)、大比例更新/删除后未及时收集统计信息,优化器仍按旧的行数、数据分布估算成本,可能误判索引有效性或连接顺序。例如:原表仅1万行时走索引范围扫描合理;涨到500万行且查询返回20%数据时,全表扫描实际更快,但旧统计信息未体现高选择性下降,仍选索引,造成慢查询。
- 定期检查 dba_tab_statistics.last_analyzed,对高频DML表设置自动收集(如Oracle的AUTO_TASK)或定制窗口任务
- 对倾斜列(如状态码、地区码)启用列级直方图,避免优化器误估谓词选择率
- 大表收集时慎用默认采样率,可指定 estimate_percent => dbms_stats.auto_sample_size 或人工测算后固定值
绑定变量窥探(Bind Peek)与参数敏感型谓词耦合
优化器首次硬解析时“偷看”绑定变量值生成计划,并缓存复用。若该值极特殊(如 status = 'CANCELED' 仅占0.1%,但首次传入的是 'ACTIVE' 占95%),后续传入其他值时仍沿用为 'ACTIVE' 生成的计划,就会错配。
- 确认是否开启绑定变量窥探:SELECT value FROM v$parameter WHERE name = 'optimizer_use_bind_aware'(11g+需结合ACS机制)
- 对明显参数敏感的SQL(如WHERE type IN (:p1, :p2)),改用字符拼接动态SQL(需防注入)或拆分为多个确定性语句
- Oracle 12c+ 可启用自适应游标共享(Adaptive Cursor Sharing),但需确保 optimizer_adaptive_features 开启且SQL满足触发条件
系统级统计信息与对象级统计信息不一致
全局统计信息(如 dba_tab_col_statistics.num_distinct)与实际数据偏差不大,但某些分区表只收集了部分分区,或索引统计未同步更新,会导致连接基数估算严重失真。典型表现是执行计划中 Cardinality 列数值离谱(如预估10行,实际返回10万行)。
- 查分区表统计:用 dba_tab_partitions 和 dba_tab_subpartitions 核对各分区 last_analyzed
- 索引统计必须单独收集:dbms_stats.gather_index_stats,尤其当索引字段存在大量NULL或数据倾斜时
- 对比执行计划中的预估行数与真实返回行数(v$sql_plan_statistics_all 中的 output_rows),定位偏差源头
隐式类型转换干扰统计信息匹配
当谓词字段为VARCHAR2,而传入绑定变量为NUMBER(如 WHERE order_no = :p_order_no,order_no是字符串类型),Oracle自动加TO_NUMBER(),导致无法使用索引,同时使基于字符串分布的统计信息完全失效,优化器被迫回退到全表扫描估算模型。
- 检查执行计划中 Predicate Information 部分是否有 filter("ORDER_NO"=TO_NUMBER(:P_ORDER_NO)) 类提示
- 应用层确保传参类型与字段定义严格一致,必要时显式转换(如 WHERE order_no = TO_CHAR(:p_order_no))
- 对已存在隐式转换的SQL,可用SQL Profile固化正确计划,避免反复抖动










