Oracle数据库性能监控依赖DBMS_STATS收集准确统计信息,因ANALYZE TABLE已弃用且功能缺失;GATHER_SCHEMA_STATS需合理设置ESTIMATE_PERCENT、METHOD_OPT等参数,并验证执行计划改善而非仅看时间戳。
oracle数据库性能监控不能只靠看awr报告或实时会话,必须让优化器“知道”数据真实分布——这依赖及时、准确的统计信息。而dbms_stats系列存储过程,就是最直接、最可控的收集入口。
为什么不能用ANALYZE TABLE
旧式ANALYZE TABLE ... COMPUTE STATISTICS已被Oracle官方弃用(10g起标记为deprecated,12c后完全不推荐)。它不维护列级直方图、不支持并行、不感知数据变更监控(STALE_STATS),且无法与自动任务协同。用它更新统计,等于把优化器蒙上眼再让它跑SQL。
-
DBMS_STATS能读取DBA_TAB_STATISTICS.STALE_STATS字段,只处理真正过时的表 - 支持
NO_INVALIDATE参数,避免批量收集触发大量游标失效和硬解析 - 可配合
DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO立即刷新脏计数,让STALE_STATS = 'YES'状态即时生效
DBMS_STATS.GATHER_SCHEMA_STATS怎么设参数才不翻车
对一个用户(schema)批量收集,GATHER_SCHEMA_STATS最常用,但默认参数在生产环境极易出问题:
-
ESTIMATE_PERCENT => DBMS_STATS.AUTO_SAMPLE_SIZE是安全选择,但小表(METHOD_OPT => 'for all columns size skewonly'强制识别倾斜列 -
DEGREE => 4比AUTO_DEGREE更可控;设为1虽安全但太慢,设为0(即CPU核数)可能压垮IO,尤其在共享存储上 -
CASCADE => TRUE必须开,否则索引统计缺失,优化器可能放弃走索引 -
GRANULARITY => 'ALL'对分区表必要,否则只统计全局,忽略分区级数据倾斜 - 千万别漏
NO_INVALIDATE => FALSE——否则已有执行计划缓存全失效,秒变高并发硬解析风暴
大表/核心表要单独控制采样率
全库统一采样率会害死大表:1TB表用1%采样,误差可能超30%;而10MB表用100%又纯属浪费。实际运维中,应按表大小分档动态设置ESTIMATE_PERCENT:
- ≤ 0.5 GB →
ESTIMATE_PERCENT => 100 - 0.5–5 GB →
ESTIMATE_PERCENT => 20 - 5–50 GB →
ESTIMATE_PERCENT => 5 - > 50 GB →
ESTIMATE_PERCENT => 1,但必须配METHOD_OPT => 'for all indexed columns size 254'保关键列直方图
这类逻辑必须封装进PL/SQL块,用DBA_SEGMENTS查大小、DBA_TAB_STATISTICS筛STALE_STATS = 'YES',再逐表调用DBMS_STATS.GATHER_TABLE_STATS。
收集后必须验证是否真生效
执行完GATHER_SCHEMA_STATS不代表万事大吉。常见假成功现象:
- 表被
NOLOGGING操作大量插入后,LAST_ANALYZED时间更新了,但NUM_ROWS仍是旧值——因为DBMS_STATS没触发重算(需确认是否加了FORCE => TRUE) -
DBA_TAB_COL_STATISTICS里某列HISTOGRAM为空,但业务SQL恰恰在这列上有范围谓词——说明METHOD_OPT没覆盖该列,或采样率太低导致直方图被跳过 - 执行计划没变?先查
V$SQL_PLAN里对应SQL的PLAN_HASH_VALUE是否刷新,再看DBA_HIST_SQLSTAT里ELAPSED_TIME_DELTA是否下降,别只盯LAST_ANALYZED时间戳
最省事的验证命令:SELECT OWNER, TABLE_NAME, NUM_ROWS, LAST_ANALYZED FROM DBA_TABLES WHERE OWNER = 'SCOTT' AND TABLE_NAME = 'EMP';——但得记住,NUM_ROWS不准不等于统计失败,要看具体SQL的执行计划是否改善。



















