判断统计信息是否过期应以DBA_TAB_STATISTICS.STALE_STATS字段为准,Oracle通过DML变更量超10%标记过期;AWR仅能辅助验证影响,如执行计划漂移或Cardinality预估失真。

AWR本身不直接记录“统计信息是否过期”,但能帮你交叉验证过期引发的实际影响——比如执行计划漂移、cardinality预估严重失真。单看DBA_TAB_STATISTICS.STALE_STATS才是判断过期的权威依据。
查dba_tab_statistics.stale_stats确认过期状态
Oracle内部通过表级DML变更量(inserts + updates + deletes)是否超过当前行数10%来标记stale_stats = 'YES'。这是最准、最轻量的判断方式。
- 先刷新监控信息:
exec dbms_stats.flush_database_monitoring_info,否则all_tab_modifications可能滞后 - 查过期表:
SELECT owner, table_name, stale_stats, last_analyzed FROM dba_tab_statistics WHERE owner IN ('PROD') AND stale_stats = 'YES' ORDER BY last_analyzed - 别只信
stale_stats字段:某些低频大事务表(如日终批处理表)可能DML没超10%,但数据分布已剧变,需人工干预
用DBA_HIST_SQL_PLAN反推统计信息是否失真
如果某SQL的plan_hash_value在AWR里频繁切换,且切换时间点与last_analyzed时间吻合,大概率是统计信息过期触发了优化器重硬解析。
- 运行:
SELECT plan_hash_value, COUNT(*), MIN(sample_time), MAX(sample_time) FROM dba_hist_sql_plan p JOIN dba_hist_sqlstat s USING (sql_id, plan_hash_value) WHERE sql_id = 'your_sql_id' AND sample_time > SYSDATE - 7 GROUP BY plan_hash_value ORDER BY MIN(sample_time) - 返回多行 → 计划漂移;再比对各
plan_hash_value出现时段,看是否紧邻某张表的last_analyzed时间 -
dba_hist_sql_plan默认每sql_id最多存1000行,高频SQL可能被截断,空结果不等于没漂移
用DISPLAY_AWR对比cardinality预估偏差
同一sql_id、不同plan_hash_value下,谓词的Cardinality预估值若相差2个数量级以上(比如预估120行 vs 实际返回8万行),基本可锁定统计信息不准——尤其当该列有直方图缺失时。
- 调用:
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR('your_sql_id', plan_hash_value => 1234567890, format => 'BASIC +PREDICATE +COST')) - 重点比对
access_predicates和filter_predicates里的Cardinality列,不是看Rows(那是实际返回) - 若预估偏差大但
stale_stats = 'NO',检查该列是否有直方图:SELECT column_name, histogram FROM dba_tab_col_statistics WHERE table_name = 'TBL_NAME' AND owner = 'PROD'
真正难的是区分“统计信息过期”和“统计信息存在但不适用”——比如分区表只收集了全局统计而没收集子分区,或函数索引列没开method_opt参数。这些不会触发stale_stats = 'YES',但同样导致计划劣化。


















