










在Oracle数据库CBO基于成本的优化器体系当中,统计信息是优化器生成合理执行计划的核心输入源。统计信息失真、缺失、过期是线上SQL性能抖动、执行计划漂移最主要诱因之一。大量生产故障根因均来自统计信息维护不当:大表批量DML之后统计信息未刷新、直方图丢失、自动收集任务窗口不合理、参考数据表统计信息被自动任务覆盖等。风哥教程本文围绕统计信息基础概念、各类统计信息收集手段、自动维护任务、统计信息删除重建、锁定解锁、备份迁移、pending发布机制、动态采样等核心技术展开完整讲解。风哥 itpux‑com
本套风哥教程面向DBA、数据库运维工程师、后端开发人员,全部实验标准化环境配置:主机名称fgedu‑net‑cn,硬件规格64G物理内存、8颗CPU;数据库实例名fgedudb,数据库名fgedudb,测试业务用户名fgedu,文件根目录统一为/fgedudb,整套实验基于Oracle19c企业版完成。风哥教程本文分为前言大纲介绍、核心理论知识、实战操作演练、总结四大模块;实战章节包含大量可直接复制运行的SQL脚本,读者可以在测试环境完整复现全部实验现象,掌握生产环境统计信息全套运维操作与风险规避要点。网上搜索风哥教程可以学习全套数据库教程
本章节为本套风哥教程理论基础,只有理解统计信息底层原理,才能够看懂执行计划基数估算偏差,处理线上因为统计信息引发的SQL性能故障。风哥教程 113257174
Oracle CBO优化器依靠统计信息计算访问路径、表连接方式的COST成本,从中选出成本最低的执行计划。统计信息存储在Oracle数据字典内部,分为多类:表统计信息、列统计信息(含直方图)、索引统计信息、系统统计信息、字典对象统计信息。
fgedu‑net‑cn为64G内存8CPU,系统统计信息采集本机真实硬件指标。失效(stale)统计信息:当表发生大量insert/update/delete,修改量超过阈值,数据库标记该对象stale_stats=YES,代表现有统计信息已经不能真实反映当前数据分布,需要重新收集。网上搜索风哥教程可以学习全套数据库教程
Oracle存在两套收集统计信息的手段:传统analyze命令与dbms_stats系统包,二者能力存在巨大差异。
注意:analyze收集的统计信息,部分字段不会被CBO完整使用,生产业务表禁止用analyze替代dbms_stats。
DBMS_STATS提供不同粒度存储过程,适配不同运维场景:
gather_database_stats:收集全库所有对象统计,耗资源,一般仅新库初始化使用,业务运行数据库不建议频繁执行。gather_schema_stats:收集指定Schema下全部表、索引统计,适合业务版本上线,大批量对象变更后使用。gather_table_stats:单张表统计收集,包含列直方图,可同时收集索引统计;生产故障排查最频繁使用。gather_index_stats:只收集索引统计,不处理表与列。gather_dictionary_stats:收集SYS等系统字典对象统计,维护数据库内部递归SQL性能。gather_system_stats:采集主机CPU、IO硬件系统统计信息。关键参数解释(适配64G内存8CPU生产环境)
estimate_percent:采样比例,DBMS_STATS.AUTO_SAMPLE_SIZE由Oracle自动选择最优采样,19c推荐优先使用。method_opt:控制直方图收集策略;FOR ALL COLUMNS SIZE AUTO自动识别倾斜列创建直方图,业务生产标准配置。degree:并行度,8CPU主机,业务收集建议设置degree=>4‑6,不能超过CPU核数。cascade:TRUE代表同步收集关联索引统计信息。no_invalidate:FALSE,收集完成直接使化相关游标,让新统计立刻生效;TRUE不会使化游标,旧游标继续沿用旧统计。granularity:针对分区表,AUTO自动处理分区、子分区、全局统计。Oracle自动维护任务AutoTask,在维护窗口执行auto optimizer stats collection任务,自动识别标记stale失效的对象,优先对失效对象收集统计信息。
默认维护窗口为每周七天夜间时间段。并不是全库全部重收集,优先处理无统计、统计过期失效对象。
生产环境常见问题:业务批量数据变更发生在白天,夜间窗口才会刷新统计,会出现白天业务运行统计信息已经失效;部分参考基础数据表,不希望自动任务覆盖已经调优完成的直方图,需要执行统计锁定。
风哥数据库教程 itpux‑com
optimizer_dynamic_sampling控制,默认级别2。动态采样是补偿手段,不能替代完整统计信息收集。风险点:动态采样采样块数有限,数据高度倾斜场景,动态采样估算依旧会出现巨大偏差。
本套风哥教程全部实战操作,操作主机fgedu‑net‑cn,数据库fgedudb,业务用户fgedu,目录/fgedudb,硬件规格64G内存8CPU。
环境说明:操作系统登录oracle用户,设置环境变量指向
fgedudb实例;大部分统计管理操作需要sysdba权限,测试业务对象使用fgedu用户。
登录操作系统oracle用户执行shell命令
#确认主机名称
hostname
#确认ORACLE_HOME路径全部指向/fgedudb
echo $ORACLE_HOME
#查看内存硬件,确认64G内存
free -h
#查看CPU,确认8CPU
lscpu
校验输出:hostname输出fgedu‑net‑cn,总内存64G,逻辑CPU数量8。
登录sqlplus / as sysdba查看相关参数
show parameter statistics_level;
show parameter optimizer_dynamic_sampling;
show parameter memory_target;
show parameter sga_target;
show parameter pga_aggregate_target;
适配64G内存主机spfile标准配置,内存分配48G留给Oracle,剩余留给操作系统。
alter system set memory_max_target=48G scope=spfile;
alter system set memory_target=48G scope=spfile;
alter system set statistics_level=TYPICAL scope=spfile;
alter system set optimizer_dynamic_sampling=2 scope=spfile;
statistics_level=TYPICAL是生产标准,开启表监控,自动统计任务依赖该参数;设置为BASIC会关闭表修改监控,自动统计无法识别stale对象。
create user fgedu identified by fgedudb default tablespace users temporary tablespace temp;
grant connect,resource to fgedu;
grant select_catalog_role to fgedu;
grant analyze any to fgedu;
grant execute on dbms_stats to fgedu;
切换fgedu用户,创建测试表,构造字段数据倾斜,用于复现直方图缺失带来的基数估算错误。
conn fgedu/fgedudb@fgedudb
create table t_stat_test(id number,status number,info varchar2(200));
--插入倾斜测试数据,status=1 100000行,status其他值各10行
declare
begin
for i in 1..100000 loop
insert into t_stat_test values(i,1,'test_info_'||i);
end loop;
for j in 2..100 loop
for k in 1..10 loop
insert into t_stat_test values(100000+j*10+k,j,'otherdata'||j);
end loop;
end loop;
commit;
end;
/
create index idx_tstat_status on t_stat_test(status);
conn / as sysdba
--查看表统计信息,行数、块、最后收集时间、是否失效
select owner,table_name,num_rows,blocks,last_analyzed,stale_stats
from dba_tab_statistics
where owner='FGEDU' and table_name='T_STAT_TEST';
--查看列统计,NDV最大最小值
select owner,table_name,column_name,num_distinct,low_value,high_value
from dba_tab_col_statistics
where owner='FGEDU' and table_name='T_STAT_TEST';
--查看直方图信息
select table_name,column_name,endpoint_number,endpoint_value
from dba_tab_histograms
where owner='FGEDU' and table_name='T_STAT_TEST';
--查看索引统计信息,重点看聚簇因子clustering_factor
select owner,index_name,leaf_blocks,clustering_factor,last_analyzed
from dba_ind_statistics
where owner='FGEDU' and index_name='IDX_TSTAT_STATUS';
dba_tab_modifications记录表insert/update/delete变更量,数据库以此判断stale状态。
SELECT
s.owner,
s.table_name,
s.last_analyzed,
s.stale_stats,
m.inserts,m.updates,m.deletes,
ROUND((m.inserts+m.updates+m.deletes)/NULLIF(s.num_rows,0)*100,2) pct_changed
FROM dba_tab_statistics s
LEFT JOIN dba_tab_modifications m
ON s.owner=m.table_owner AND s.table_name=m.table_name AND m.partition_name IS NULL
WHERE s.owner='FGEDU'
ORDER BY pct_changed DESC NULLS LAST;
conn fgedu/fgedudb@fgedudb
analyze table t_stat_test compute statistics;
--analyze不会生成直方图,查询dba_tab_histograms无记录
select * from dba_tab_histograms where owner='FGEDU' and table_name='T_STAT_TEST';
可以观察到analyze收集完成,不会生成直方图,倾斜字段无法拿到倾斜分布数据,CBO基数估算会出错。
conn / as sysdba
exec dbms_stats.gather_table_stats(
ownname=>'FGEDU',
tabname=>'T_STAT_TEST',
estimate_percent=>dbms_stats.auto_sample_size,
method_opt=>'FOR ALL COLUMNS SIZE AUTO',
degree=>4,
cascade=>true,
no_invalidate=>false
);
执行完毕,再次查询dba_tab_histograms,status字段会自动生成直方图。
exec dbms_stats.gather_schema_stats(
ownname=>'FGEDU',
estimate_percent=>dbms_stats.auto_sample_size,
method_opt=>'FOR ALL COLUMNS SIZE AUTO',
degree=>4,
cascade=>true
);
exec dbms_stats.gather_index_stats(ownname=>'FGEDU',indname=>'IDX_TSTAT_STATUS',degree=>4);
系统统计分noworkload与workload模式,workload模式需要业务运行一段时间采集真实IO、CPU负载。
--开始采集workload系统统计,业务运行一段时间
exec dbms_stats.gather_system_stats(gathering_mode=>'START');
--业务运行一段时间之后停止采集并保存
exec dbms_stats.gather_system_stats(gathering_mode=>'STOP');
--查看已经采集的系统统计
select * from sys.aux_stats$;
SELECT client_name,status,group_id
FROM dba_autotask_client
WHERE client_name='auto optimizer stats collection';
select window_name,repeat_interval,enabled,resource_plan
from dba_scheduler_windows;
--关闭自动统计任务
begin
dbms_autotask_admin.disable(client_name=>'auto optimizer stats collection');
end;
/
--开启自动统计任务
begin
dbms_autotask_admin.enable(client_name=>'auto optimizer stats collection');
end;
/
生产环境不建议直接关闭自动统计任务;对于个别不需要自动刷新的表,优先使用LOCK_TABLE_STATS锁定单表统计,而不是全局关闭任务。
⚠生产环境谨慎执行,删除之后对象无统计,依赖动态采样估算。
exec dbms_stats.delete_table_stats(ownname=>'FGEDU',tabname=>'T_STAT_TEST');
锁定之后自动任务、手工gather_table_stats均不能覆盖该表统计,适合码表、已经调优好直方图的对象。
begin
dbms_stats.lock_table_stats(ownname=>'FGEDU',tabname=>'T_STAT_TEST');
end;
/
锁定之后再执行gather_table_stats会报ORA‑20005对象统计信息被锁定。
begin
dbms_stats.unlock_table_stats(ownname=>'FGEDU',tabname=>'T_STAT_TEST');
end;
/
select owner,table_name,stattype_locked
from dba_tab_statistics
where stattype_locked is not null;
原理:创建一张普通中转表stattab,把统计信息导出存入这张表,expdp把这张表导出dmp文件传输到目标库impdp导入,再执行import把统计信息写回数据字典。风哥数据库教程 itpux‑com
conn / as sysdba
exec dbms_stats.create_stattab(stattab=>'STATS_STG_TAB',ownname=>'FGEDU',tblspace=>'USERS');
begin
dbms_stats.export_table_stats(
ownname=>'FGEDU',
tabname=>'T_STAT_TEST',
stattab=>'STATS_STG_TAB',
statown=>'FGEDU'
);
end;
/
之后使用expdp导出FGEDU.STATS_STG_TAB这张普通表,dmp文件路径指定为/fgedudb/dump。
expdp简要示例:
expdp fgedu/fgedudb@fgedudb directory=DATA_PUMP_DIR dumpfile=stats_stg.dmp tables=STATS_STG_TAB logfile=stats_stg.log
dmp文件拷贝到目标数据库服务器,impdp导入该表。
begin
dbms_stats.import_table_stats(
ownname=>'FGEDU',
tabname=>'T_STAT_TEST',
stattab=>'STATS_STG_TAB',
statown=>'FGEDU'
);
end;
/
pending模式收集统计不会立刻生效,先放在pending区域;DBA验证业务SQL性能没有退化,再执行发布,切换为正式统计。
exec dbms_stats.set_global_prefs('PUBLISH','FALSE');
此时后续所有gather收集的统计,全部存入pending待发布区域,不会直接启用。
exec dbms_stats.gather_table_stats(
ownname=>'FGEDU',
tabname=>'T_STAT_TEST',
estimate_percent=>dbms_stats.auto_sample_size,
method_opt=>'FOR ALL COLUMNS SIZE AUTO',
degree=>4,
cascade=>true
);
收集完成,查询正式dba_tab_statistics不会更新;查询pending视图查看待发布统计。
select table_name,num_rows,last_analyzed from dba_tab_pending_stats where owner='FGEDU';
--发布单表pending统计,正式生效
begin
dbms_stats.publish_pending_stats(ownname=>'FGEDU',tabname=>'T_STAT_TEST');
end;
/
--关闭全局pending模式,恢复默认收集直接发布
exec dbms_stats.set_global_prefs('PUBLISH','TRUE');
动态采样参数optimizer_dynamic_sampling,级别0关闭,默认2。
alter session set optimizer_dynamic_sampling=0;
此时关闭动态采样,如果表没有统计,CBO完全没有额外补偿,基数估算偏差巨大。
explain plan for
select /*+ dynamic_sampling(t 2) */ * from fgedu.t_stat_test t where status=1;
select * from table(dbms_xplan.display());
执行计划Note部分会输出‑ dynamic statistics used: dynamic sampling (level=2)代表动态采样已启用。
dbms_xplan.display_cursor拿到真实执行计划,对比E‑ROWS预估行数与A‑ROWS实际行数;二者差距巨大优先怀疑统计信息问题。dba_tab_statistics查看last_analyzed、stale_stats;查询dba_tab_modifications确认表DML变更占比。dba_tab_histograms,倾斜字段是否缺少直方图。stattype_locked字段。FOR ALL COLUMNS SIZE AUTO。本套风哥教程完整覆盖Oracle优化器统计信息整套运维知识,从统计信息分类、analyze与dbms_stats差异、各类粒度统计收集操作、系统统计信息,到自动维护任务、统计信息锁定解锁、备份迁移、pending待发布机制、动态采样理论与全套实战命令。
DBMS_STATS包;analyze仅保留用于检测行迁移、行链接场景。FOR ALL COLUMNS SIZE AUTO,自动识别倾斜列生成直方图;不要固定size 1关闭直方图,极易引发基数估算错误。LOCK_TABLE_STATS锁定单表统计,防止自动任务覆盖调优成果。no_invalidate=>false会使化游标,让新统计快速生效,但会带来短暂硬解析压力,需要评估业务高峰窗口。全部脚本建议读者在测试环境完整复现,理解每一条命令的输出、风险边界,再应用到真实生产运维工作。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。