dbms_stats.gather_table_stats更可靠,因analyze table自10g起已过时:不收集直方图、不支持并行、不更新列级统计(如num_distinct)、不填充cbo所需元数据结构;而dbms_stats能完整填充user_tab_statistics等视图,确保基数估算准确。

DBMS_STATS.gather_table_stats 为什么比 ANALYZE TABLE 更可靠
Oracle 10g 以后,ANALYZE TABLE 已被明确标记为过时,它不收集直方图、不支持并行、不更新列级统计(如 NUM_DISTINCT 或 DENSITY),更关键的是:它完全绕过 CBO 所需的统计元数据结构。而 DBMS_STATS.gather_table_stats 是唯一能完整填充数据字典视图(如 USER_TAB_STATISTICS、USER_TAB_COL_STATISTICS)的机制。
常见错误现象:ANALYZE TABLE emp COMPUTE STATISTICS 执行后,SELECT NUM_ROWS FROM USER_TABLES WHERE TABLE_NAME='EMP' 可能返回非 NULL 值,但 SELECT NUM_DISTINCT FROM USER_TAB_COL_STATISTICS WHERE TABLE_NAME='EMP' AND COLUMN_NAME='DEPT_ID' 仍为空 —— 这会导致 CBO 在连接估算时把 DEPT_ID 当作全唯一值处理,严重低估基数。
- 必须用
DBMS_STATS,不能用ANALYZE替代 - 即使只改一行数据,也应触发统计更新(尤其对小表或配置表)
-
cascade => TRUE要显式指定,否则索引统计不会自动刷新
estimate_percent 参数设多少才不翻车
默认值 DBMS_STATS.AUTO_SAMPLE_SIZE 看似省心,但在某些场景下反而危险:当表存在严重数据倾斜(比如某 STATUS 列 95% 是 'A',其余值极少),自动采样可能错过稀有值分布,导致直方图缺失或不准,CBO 就会误判 WHERE STATUS = 'Z' 的选择率。
实操建议:
- 稳定业务表(如订单主表):用
estimate_percent => 20,兼顾精度与耗时 - 小表(estimate_percent => 100,避免采样误差
- 大宽表(列数 > 50)且变更频繁:降低采样率(如
5),但必须配合method_opt => 'FOR ALL COLUMNS SIZE AUTO'强制生成直方图 - 绝对不要设为
0—— 这会触发“无采样”逻辑,等价于不收集统计
cascade => TRUE 不是可选项,而是必填项
很多人调用 gather_table_stats 时不加 cascade,以为“表统计有了就行”。但 CBO 在决定是否走索引时,极度依赖索引本身的统计信息(比如 CLUSTERING_FACTOR)。如果只更新表统计而忽略索引,CLUSTERING_FACTOR 仍维持旧值,CBO 就可能认为某个索引“很散”,从而放弃使用它,转而选择全表扫描。
典型症状:执行计划里本该出现的 INDEX RANGE SCAN 变成了 TABLE ACCESS FULL,且 USER_INDEXES.CLUSTERING_FACTOR 明显高于表行数(比如表有 10 万行,CF 却是 80 万)。
- 所有生产环境调用
gather_table_stats必须带cascade => TRUE - 若只想更新特定索引,可用
gather_index_stats单独处理 -
cascade => FALSE仅适用于调试或极特殊场景(如临时禁用索引统计更新)
什么时候该用 gather_schema_stats 而不是单表
批量操作(如 ETL 加载后)、跨多表关联的业务模块上线、或发现大量表统计过期(LAST_ANALYZED 超过 7 天),这时逐个调用 gather_table_stats 效率低且易遗漏。但 gather_schema_stats 不是“一键全量”的银弹 —— 它默认跳过临时表、物化视图日志表,且对大对象(LOB)列默认不收集统计。
关键细节:
- 必须显式传入 schema 名,如
'SCOTT';传空字符串或NULL会报错 ORA-20000 - 加
degree => 4可启用并行,但要注意 PGA 内存压力 - 慎用
options => 'GATHER AUTO':它只扫“被认为过期”的表,判断逻辑隐晦(基于修改次数+时间),容易漏掉真正需要更新的表 - 首次初始化新 schema 时,优先用
options => 'GATHER COMPLETE',确保全覆盖
最常被忽略的一点:gather_schema_stats 不会自动更新数据字典基表(如 OBJ$、COL$)的统计 —— 这些必须由 gather_database_stats 单独处理,否则涉及 DBA_* 视图的查询可能出错。











