在Oracle数据库中,优化器依赖表和列的统计信息来生成最优的执行计划,因此定期收集准确的统计信息是保障SQL性能的重要工作。下面我们先来看一张示意图,直观了解统计信息的作用范围。

统计信息的作用与分类
统计信息主要包含表的行数、块数,列的不同值数量、空值比例、数据分布直方图等内容。表和列的统计信息过期或者缺失时,优化器可能会选择全表扫描等低效的执行方式,导致查询耗时增加。
常用收集工具:DBMS_STATS包
Oracle提供了DBMS_STATS包来统一管理统计信息,相比传统的ANALYZE命令,它支持更灵活的参数配置,还能收集直方图等更复杂的统计信息,是目前官方推荐的首选方式。
1. 收集单表及所有列的统计信息
使用GATHER_TABLE_STATS存储过程可以一次性收集指定表的表级统计信息和所有列的统计信息,基本语法如下:
-- 收集SCOTT用户下EMP表的统计信息
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(
ownname => 'SCOTT', -- 表所属的用户名
tabname => 'EMP', -- 表名
estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE, -- 自动选择采样比例
method_opt => 'FOR ALL COLUMNS SIZE AUTO', -- 自动为列生成直方图
cascade => TRUE, -- 同时收集索引的统计信息
force => TRUE -- 即使表被锁定也强制收集
);
END;
/其中estimate_percent参数如果设置为100,会全表扫描收集统计信息,适合小表;大表建议使用AUTO_SAMPLE_SIZE让Oracle自动选择合理的采样比例,平衡准确性和收集效率。
2. 仅收集指定列的统计信息
如果只需要更新某几个列的统计信息,不需要全表重新收集,可以使用GATHER_COLUMNS_STATS存储过程,示例如下:
-- 仅收集EMP表的EMPNO和DEPTNO列的统计信息
BEGIN
DBMS_STATS.GATHER_COLUMNS_STATS(
ownname => 'SCOTT',
tabname => 'EMP',
colname => 'EMPNO,DEPTNO', -- 要收集统计信息的列名,多个列用逗号分隔
estimate_percent => 30, -- 采样比例30%
method_opt => 'FOR COLUMNS EMPNO SIZE 10, DEPTNO SIZE AUTO' -- 为EMPNO列生成10个桶的直方图
);
END;
/统计信息的查看与验证
收集完成后,可以通过数据字典视图验证统计信息是否生效,常用的查询语句如下:
-- 查看表的统计信息 SELECT table_name, num_rows, blocks, last_analyzed FROM dba_tables WHERE owner = 'SCOTT' AND table_name = 'EMP'; -- 查看列的统计信息 SELECT column_name, num_distinct, num_nulls, density, last_analyzed FROM dba_tab_columns WHERE owner = 'SCOTT' AND table_name = 'EMP';
注意事项
- 生产环境收集统计信息建议在业务低峰期执行,避免采样过程占用过多系统资源。
- 对于数据变化频繁的表,可以设置自动统计信息收集任务,Oracle默认会在维护窗口自动运行。
- 如果发现收集统计信息后执行计划变差,可以使用DBMS_STATS.RESTORE_TABLE_STATS恢复之前的统计信息。
- 不要对临时表、外部表使用全表采样的收集方式,临时表建议在每个会话中单独收集统计信息。
注意:统计信息收集后不会立即对所有正在运行的SQL生效,已经解析的游标需要失效后才会重新生成执行计划,必要时可以刷新共享池或者重启实例让新统计信息生效。
Oracle统计信息表统计列统计DBMS_STATS修改时间:2026-05-24 23:42:34