一、更新前准备:
确认当前统计信息是否过期
1. 查看某张表/索引最近一次收集时间
-- 表级
SELECT owner,table_name,num_rows,last_analyzed
FROM all_tables
WHERE owner='PROD' AND table_name='ORDERS';
-- 索引级
SELECT owner,index_name,num_rows,last_analyzed
FROM all_indexes
WHERE owner='PROD' AND table_name='ORDERS';
若 num_rows 为空或与真实行数差距大,或 last_analyzed 是一周以前,即可判定需要更新
2. 记录真实行数(用于更新后比对)
SELECT COUNT(*) FROM prod.orders;
二、更新统计信息的 4 种典型场景
1. 只更新一张表(含所有列、所有索引)
-- 100 表示采样 100% 行,FALSE 表示不并行
DBMS_STATS.GATHER_TABLE_STATS(
ownname => 'PROD',
tabname => 'ORDERS',
estimate_percent => 100,
method_opt => 'FOR ALL COLUMNS SIZE AUTO',
cascade => TRUE); -- TRUE 表示同时收集索引统计信息
2. 仅更新某个列的统计信息
DBMS_STATS.GATHER_COLUMN_STATS('PROD','ORDERS','CREATE_TIME');
3、仅更新某个索引
DBMS_STATS.GATHER_INDEX_STATS('PROD','IDX_ORDERS_CT');
4、批量更新整个模式(夜间作业最常用)
DBMS_STATS.GATHER_SCHEMA_STATS(
ownname => 'PROD',
estimate_percent => 100,
block_sample => FALSE,
method_opt => 'FOR ALL COLUMNS SIZE AUTO',
cascade => TRUE);
若数据量极大,可把 estimate_percent 改成 DBMS_STATS.AUTO_SAMPLE_SIZE 让优化器自己决定采样比例
三、更新后必做:清空计划缓存,让新统计信息立即生效
CALL SP_CLEAR_PLAN_CACHE();
说明:DM 会把 SQL 执行计划缓存在内存,不清缓存则老计划可能继续沿用,导致性能无变化
四、更新后检查:确认统计信息已变化
-
再次查询
all_tables/all_indexes的num_rows与last_analyzed,应与刚才COUNT(*)一致且时间已刷新 -
用系统包查看详细直方图、密度等
-- 表级
DBMS_STATS.TABLE_STATS_SHOW('PROD','ORDERS');
-- 索引级
DBMS_STATS.INDEX_STATS_SHOW('PROD','IDX_ORDERS_CT');
-- 列级
DBMS_STATS.COLUMN_STATS_SHOW('PROD','ORDERS','CREATE_TIME');
- 观察 SQL 执行计划是否改变
EXPLAIN SELECT … FROM prod.orders WHERE create_time >= DATE '2025-11-01';
若原走全表扫描现改为索引范围扫描,且估算行数与实际行数接近,即证明统计信息已生效
五、可自动化的“作业”模板(一次配置,每周自动跑)
- 用 SYSDBA 登录管理工具,右键“代理”→“作业”→“新建作业”。
- 步骤里贴入以下语句:
DBMS_STATS.GATHER_SCHEMA_STATS('PROD',100,FALSE,'FOR ALL COLUMNS SIZE AUTO',TRUE);
CALL SP_CLEAR_PLAN_CACHE();
-
调度里设“每周日 22:15 执行”。
-
保存后可右键“查看作业历史信息”确认是否成功
六、常见注意点
- 生产库建议在业务低峰期操作;采样比例越高,锁表时间越长。
- 若表做了大批量
INSERT/UPDATE/DELETE,事后立即收集统计信息可避免后续 SQL 走错计划。 - 统计信息本身存放在系统表,可通过
DBA_TAB_STATS_HISTORY查询历史,支持回滚到指定时间点的统计信息。
按照以上步骤即可完成“更新→验证→自动化”的闭环。