深入学习Oracle 的统计信息
一、概念定义
Oracle 的统计信息(Optimizer Statistics)是优化器(CBO,基于成本的优化器)用来估算 SQL 执行代价的一组元数据。它描述的是数据库对象的数据分布特征,本身并不等同于业务数据。
按对象类型划分,主要包括四类:
| 类别 | 主要内容 |
|---|---|
| 表统计 | 行数(NUM_ROWS)、数据块数(BLOCKS)、平均行长度(AVG_ROW_LEN)、空块数等 |
| 列统计 | 不同值个数(NDV)、空值数、选择性(DENSITY)、直方图 |
| 索引统计 | 索引层级(BLEVEL)、叶子块数、聚簇因子(CLUSTERING_FACTOR)、不同键值数 |
| 系统统计 | CPU 与单块读、多块读的代价常量,用于代价模型换算 |
此外还有扩展统计(多列相关性)、表达式统计等辅助形式。
二、作用与适用场景
统计信息是 CBO 生成执行计划的必要输入,其核心作用是让优化器回答三个问题:
- 要返回多少行:基数(Cardinality)估算;
- 走哪条路径最便宜:全表扫描、索引扫描还是索引快速全扫;
- 表之间怎么连接:连接顺序(Join Order)与连接方式(Nested Loop、Hash Join、Merge Join)。
因此它直接影响访问路径、连接顺序、连接方法和并行度选择。典型需要重点关注的场景包括:
- 大批量导入、删除、更新后,数据分布发生显著变化;
- 新上线 SQL 突然变慢、执行计划发生异常变化;
- 分区表新增分区、历史分区数据归档;
- 表数据倾斜严重、存在多列相关性条件;
- 从测试环境迁移到生产环境,需要复用或重建统计信息。
需要明确的是:统计信息是“让优化器了解数据长什么样”,不是“直接告诉数据库该怎么执行”。
三、工作机制
- 解析与转换:SQL 解析后先做查询转换(视图合并、子查询展开、谓词推入等)。
- 基数估算:优化器用列统计计算选择性,常见关系为
选择性 ≈ 1 / NDV;有直方图时按桶描述倾斜分布;多列相关条件则依赖扩展统计。 - 代价计算:结合表、索引统计与系统统计,估算 I/O 代价与 CPU 代价,得到各候选计划的 COST。
- 计划选择:在候选计划中选取代价最低者,形成最终执行计划并缓存到共享池。
- 统计信息维护:Oracle 从 10g 起内置自动统计信息收集任务,在维护窗口内对缺失或过期的对象收集统计信息;19c 起还引入实时统计信息(Real-Time Statistics),在常规 DML 过程中补充最基本的统计信息,降低优化器被过时统计信息误导的风险,但它不能取代自动收集任务。
- 过期判定:当对象被 DML 修改的行数超过总行数约 10% 时,通常会被标记为过期(STALE)。
四、相关对象与观察入口
相关系统视图
| 视图名 | 用途 | 与本概念的关联 |
|---|---|---|
| DBA_TAB_STATISTICS | 显示所有表的优化器统计信息 | 查看表级统计、STALE_STATS、LAST_ANALYZED、锁定状态 |
| DBA_TAB_COL_STATISTICS | 列统计与直方图概要 | 查看 NDV、DENSITY、直方图桶数 |
| DBA_IND_STATISTICS | 索引优化器统计信息 | 查看 BLEVEL、叶子块、聚簇因子 |
| DBA_TAB_HISTOGRAMS | 表的列直方图明细 | 判断倾斜列的分布描述是否合理 |
| DBA_OPTSTAT_OPERATIONS | 统计信息操作历史 | 查看 schema、database 级收集操作记录 |
| DBA_OPTSTAT_OPERATION_TASKS | 统计信息收集任务明细 | 观察并发收集任务执行情况 |
| DBA_SCHEDULER_JOBS | 调度作业信息 | 确认自动统计信息收集任务是否存在并启用 |
其他观察入口
- DBMS_STATS 包:收集、删除、锁定、恢复、导出导入统计信息的主要接口,如 GATHER_TABLE_STATS、GATHER_SCHEMA_STATS、GATHER_DATABASE_STATS、LOCK_TABLE_STATS、RESTORE_TABLE_STATS、PUBLISH_PENDING_STATS。
- 执行计划:执行计划中的 Rows、Cost、Cardinality 与统计信息估算直接对应,可用于反向验证统计信息是否失真。
- 优化器动态采样参数
optimizer_dynamic_sampling:缺少统计信息时,优化器可在解析阶段做小范围采样估算。 - 10053 事件:可输出优化器代价计算与计划选择过程。
如何“利用”这些统计信息
实践中通常从五个方向使用:
- 保持统计信息新鲜:确保自动收集任务正常运行,不要在无替代方案时直接关闭;大表或特殊表可按需手动收集。
- 收集时控制代价与质量:通过采样比例、并行度、直方图策略、是否级联收集索引等参数平衡准确性与资源消耗。
- 定期检查过期情况:用 STALE_STATS 与 LAST_ANALYZED 组合判断对象统计是否仍可用。例如:
SELECT owner, table_name, partition_name, stale_stats, last_analyzed
FROM dba_tab_statistics
WHERE table_name = UPPER('&table_name');
- 稳定对象锁定统计信息:对数据基本不变的归档表、历史表锁定统计信息,避免自动任务反复收集;需要更新时先解锁。
- 变更前留后路:重要表在收集或结构调整前备份统计信息,计划异常时用恢复功能回退;也可用待定统计信息(Pending Statistics)先验证再发布。
- 补充特殊分布信息:倾斜列使用直方图,多列相关条件使用扩展统计;分区大表可启用增量统计。
- 统计信息无法解决时:配合 SQL 计划管理(SQL Plan Management)固定或演化执行计划,避免计划反复波动。
五、常见误区与边界
- “统计信息准确,执行计划就一定最优”:不成立。计划还受代价模型、绑定变量窥探、参数设置、并行度、内存配置等影响。
- “采样比例越高越好”:大表 100% 采样代价很高;对分布均匀的表,合理采样已足够,关键是分布特征是否被正确描述。
- “执行计划变了就一定是统计信息问题”:游标失效、绑定变量、参数变更、版本升级、索引变化都可能改变计划,需结合执行计划历史与 AWR 判断。
- “用 ANALYZE TABLE 收集统计信息”:Oracle 推荐使用 DBMS_STATS,ANALYZE 主要用于结构校验,收集统计信息存在局限。
- “统计信息锁定后还能自动更新”:锁定会阻止自动收集,需先解锁。
- “收集完统计信息,旧游标一定立刻用新统计”:已缓存游标是否立即失效与 NO_INVALIDATE 等参数有关,否则可能仍沿用旧计划。
- “DBMS_STATS 能收集所有信息”:例如行迁移/链接计数(CHAIN_CNT)不由其收集,需用 ANALYZE 的 LIST CHAINED ROWS。
- “删除统计信息可以解决计划问题”:删除后优化器可能转向动态采样或默认估算,结果未必更优,不能作为常规手段。
- 直方图有边界:桶数上限为 254;对不适合的列建直方图反而可能误导优化器。
六、延伸知识
- 动态采样:缺少统计信息时由优化器临时采样估算,级别 0 表示关闭;级别越高采样块越多,但解析开销也越大。
- 实时统计信息:19c 起在 DML 过程中维护基础统计,属于自动收集的补充。
- 待定统计信息与统计信息恢复:用于在正式发布前验证统计信息变更的影响,或异常时快速回退。
- 增量统计信息:面向分区表,减少全表重新收集的开销。
- 扩展统计:描述多列之间的相关性,改善多列等值、范围条件的基数估算。
- SQL 计划管理:当统计信息变化导致计划不稳定时,用于固定或演化执行计划。
浙公网安备 33010602011771号