第2章 统计信息
2.1、统计信息主要分类
表的统计信息
总行数(num_rows)、块数(blocks)、平均长度(avg_row_len),可通过DBA_TABLES获取;
列的统计信息
列的基数、列的空值数量、列的数据分配(直方图),可通过DBA_TAB_COL_STATISTICS获取;
select a.column_name, b.num_rows, a.num_distinct Cardinality, round(a.num_distinct / b.num_rows * 100, 2) selectivity, a.HISTOGRAM, a.num_buckets from dba_tab_col_statistics a, dba_tables b where a.owner = b.owner and a.table_name = b.table_name and a.owner = 'SCOTT' and a.table_name = 'TEST';
复制
索引的统计信息
索引blevel(索引高度-1)、叶子块的个数(leaf_blocks)以及集群因子(clustering_factor),可通过DBA_INDEXES获取;
单独对索引收集统计信息: begin dbms_stats.gather_index_stats(ownername => 'SCOTT', indname => 'IDX_T_STATS_ID'); end;
复制
系统的统计信息
数据字典的统计信息
动态性能视图基表的统计信息
2.2、统计信息参数设置
begin
dbms_stats.gather_table_stats(ownname => 'TAB_OWNER',
tabname => 'TAB_NAME',
estimate_percent => '根据表大小设置',
method_opt => 'for all columns size repeat',
no_invalidate => FALSE,
degree => '根据表大小,CPU资源和负载设置',
granularity => 'AUTO',
cascade => TRUE);
end;
ownname表示表的拥有者,不区分大小写;
tabname表示表名字,不区分大小写;
granularity表示收集统计信息的粒度,该选项只对分区表生效,默认为AUTO;
estimate_percent表示采样率,范围是0.000001 ~ 100;
method_opt用于控制收集直方图策略;
> method_opt => 'for all columns size 1'表示所有列都不收集直方图;
> method_opt => 'for all columns size skewonly'表示对表中所有列收集自动判断是否收集直方图;
> method_opt => 'for all columns size auto'表示对出现在where条件中的列自动判断是否收集直方图;
> method_opt => 'for all columns size repeat'表示当前有哪些列收集了直方图,现在就对哪些列收集直方图;
> method_opt => 'for columns col1 size skewonly'表示单独对列col1收集直方图,对于其他列,如果之前收集过直方图,现在也收集直方图;
no_invalidate:表示共享池中涉及到该表的游标是否立即失效,设置为FALSE代表立即失效;
degree表示收集统计信息的并行度,默认为NULL;
cascade表示收集表的统计信息的时候,是否级联收集索引的统计信息;
复制
2.3、检查统计信息是否过期
dba_tab_statistics:列stale_stats为YES,代表统计信息过期;
当表中有超过10%的数据发生变化(insert、update、delete),就会引起统计信息过期;
2.3.1、如果一个SQL有多个表关联或视图嵌套,如何快速检查SQL语句中所有的表统计信息是否过期?
select * from scott.emp e, scott.dept d where e.deptno = d.deptno;
生成执行plan_table:
explain plan for
select * from scott.emp e, scott.dept d where e.deptno = d.deptno;
获取是否过期:
select owner, table_name, object_type, stale_stats, last_analyzed
from dba_tab_statistics
where (owner, table_name) in
(select object_owner, object_name
from plan_table
where object_type like '%TABLE%'
union
select table_owner, table_name
from dba_indexes
where (owner, index_name) in
(select object_owner, object_name
from plan_table
where object_type like '%INDEX%'));
获取过期原因:
select *
from all_tab_modifications
where (table_owner, table_name) in
(select object_owner, object_name
from plan_table
where object_type like '%TABLE%'
union
select table_owner, table_name
from dba_indexes
where (owner, index_name) in
(select object_owner, object_name
from plan_table
where object_type like '%INDEX%'));
复制
2.4、扩展统计信息
扩展统计信息只能用于等值查询,不能用于非等值查询;
create table scott.t as select level as id, level || 'a' as a, level || level || 'b' as b from dual connect by level <= 1000; insert into scott.t select * from scott.t ; select count(*) from scott.t; --2048000 begin dbms_stats.gather_table_stats(ownname => 'SCOTT', tabname => 'T', estimate_percent => 100, method_opt => 'for all columns size skewonly', no_invalidate => FALSE, degree => 1, cascade => TRUE); end; select a.column_name, b.num_rows, a.num_distinct Cardinality, round(a.num_distinct / b.num_rows * 100, 2) selectivity, a.HISTOGRAM, a.num_buckets from dba_tab_col_statistics a, dba_tables b where a.owner = b.owner and a.table_name = b.table_name and a.owner = 'SCOTT' and a.table_name = 'T'; create index idx1 on scott.t(a) ; create index idx2 on scott.t(a,b) ; select dbms_stats.create_extended_stats(ownname => 'SCOTT',tabname => 'T',extension => '(A,B)') from dual ; -- SYS_STUNA$6DVXJXTP05EH56DTIR0X begin dbms_stats.gather_table_stats(ownname => 'SCOTT', tabname => 'T', estimate_percent => 100, method_opt => 'for columns SYS_STUNA$6DVXJXTP05EH56DTIR0X size skewonly', no_invalidate => FALSE, degree => 1, cascade => TRUE); end; select a.column_name, b.num_rows, a.num_distinct Cardinality, round(a.num_distinct / b.num_rows * 100, 2) selectivity, a.HISTOGRAM, a.num_buckets from dba_tab_col_statistics a, dba_tables b where a.owner = b.owner and a.table_name = b.table_name and a.owner = 'SCOTT' and a.table_name = 'T';
复制
2.5、动态采样
默认情况是level=2;
2.5.1、动态采样级别
当系统中有全局临时表,就需要动态采样,因为全局临时表无法收集统计信息,建议对全局临时表至少启用level 4进行采样;
当执行计划中标的Rows估算有严重偏差的时候,列入相关列问题,或者量表关联有多个连接列,关联之后Rows算少,或者where过滤条件中对列使用了substr、instr、like,又或者是where过滤条件中有非等值过滤,或者group by之后导致Rows估算错误,此时我们可以考虑动态采样,同样,建议动态采样至少设置为level 4;
level 0:不启用动态采样。 level 1:当表(非分区表)没有收集过统计信息并且这个表要与另外的表进行关联(不能是单表访问),同时该表没有索引,表的数据块必须大于32个,满足这些条件的时候,Oracle会随机扫描表中32个数据块,然后评估返回的Rows。 level 2:对没有收集过统计信息的表启用动态采样,采样的块数为64个,如果表的块数小于64个,表有多少个块就会采样多少个块。 level 3:对没有收集过统计信息的表启用动态采样,采样的块数为64个。如果表已经收集过统计信息,但是优化器不能准确地估算出返回的Rows,而是靠猜,比如WHERE SUBSTR(owner,1,3),这时会随机扫描64个数据块进行采样。 level 4:对没有收集过统计信息的表启用动态采样,采样的块数为64个。如果表已经收集过统计信息,但是表有两个或者两个以上过滤条件(AND/OR),这时会随机扫描64个数据块进行采样,相关列问题就必须启用至少level 4进行动态采样。level4采样包含了level 3的采样数据。 level 5:收集满足level 4采样条件的数据,采样的块数为128个。 level 6:收集满足level 4采样条件的数据,采样的块数为256个。 level 7:收集满足level 4采样条件的数据,采样的块数为512个。 level 8:收集满足level 4采样条件的数据,采样的块数为1 024个。 level 9:收集满足level 4采样条件的数据,采样的块数为4 086个。 level 10:收集满足level 4采样条件的数据,采样表中所有的数据块。 level 11:Oracle自动判断如何采样,采样的块数由Oracle自动决定。
复制
SCOTT@o11g>create table t_dyna as select * from dba_objects;
SCOTT@o11g>alter session set optimizer_dynamic_sampling=3;
SCOTT@o11g>select /*+ dynamic_sampling(3) */ * from t_dyna where substr(owner,4,3)='LIC';
复制
2.6、定制统计信息收集策略
脚本:收集统计信息过期了或者表从没收集过统计信息的表的统计信息
declare cursor stale_table is select owner, segment_name, case when segment_size < 1 then 100 when segment_size >= 1 and segment_size <= 5 then 50 when segment_size > 5 then 30 end as percent, 6 as degree from (select owner, segment_name, sum(bytes / 1024 / 1024 / 1024) segment_size from DBA_SEGMENTS where owner = 'SCOTT' and segment_name in (select table_name from DBA_TAB_STATISTICS where (last_analyzed is null or stale_stats = 'YES') and owner = 'SCOTT') group by owner, segment_name); begin dbms_stats.flush_database_monitoring_info; for stale in stale_table loop dbms_stats.gather_table_stats(ownname => stale.owner, tabname => stale.segment_name, estimate_percent => stale.percent, method_opt => 'for all columns size repeat', degree => stale.degree, cascade => true); end loop; end; /
复制获取全局临时表信息(需单独收集统计信息):
select b.OBJECT_OWNER, b.OBJECT_NAME, a.temporary, sql_text from dba_tables a, v$sql_plan b, v$sql c where a.owner = b.object_owner and a.temporary = 'Y' and a.table_name = b.OBJECT_NAME and b.sql_id = c.sql_id;
复制
最后修改时间:2019-10-28 12:46:35
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。
文章被以下合辑收录
评论
相关阅读
【纯干货】Oracle 19C RU 19.27 发布,如何快速升级和安装?
Lucifer三思而后行
779次阅读
2025-04-18 14:18:38
Oracle RAC 一键安装翻车?手把手教你如何排错!
Lucifer三思而后行
659次阅读
2025-04-15 17:24:06
Oracle数据库一键巡检并生成HTML结果,免费脚本速来下载!
陈举超
585次阅读
2025-04-20 10:07:02
【ORACLE】你以为的真的是你以为的么?--ORA-38104: Columns referenced in the ON Clause cannot be updated
DarkAthena
541次阅读
2025-04-22 00:13:51
【活动】分享你的压箱底干货文档,三篇解锁进阶奖励!
墨天轮编辑部
527次阅读
2025-04-17 17:02:24
【ORACLE】记录一些ORACLE的merge into语句的BUG
DarkAthena
509次阅读
2025-04-22 00:20:37
一页概览:Oracle GoldenGate
甲骨文云技术
490次阅读
2025-04-30 12:17:56
火焰图--分析复杂SQL执行计划的利器
听见风的声音
464次阅读
2025-04-17 09:30:30
3月“墨力原创作者计划”获奖名单公布
墨天轮编辑部
382次阅读
2025-04-15 14:48:05
OR+DBLINK的关联SQL优化思路
布衣
380次阅读
2025-05-05 19:28:36