一、 动态采样 Dynamic Sampling
1. 引入原因
oracle默认认为where条件中出现的各列彼此是没有关联的,以此估算出的基数值可能不准,导致选错执行计划。
例如学生表有10000行,要查询9月出生并且是处女座的人数,如果当作这两个条件没有关联,默认的概率计算方法是(1/12) * (1/12) = 1/144,预估的返回值约为69。但是显然这两个条件是有关联的,9月出生的人大多都是处女座,实际返回行数应该远大于69,而错误的基数预估,就可能导致选错执行计划。
为了较准确地估算where条件中出现有关联关系的列时所有条件组合的选择率,进而得到较准确的基数值,9i R2版本引入了动态采样技术。另外动态采样可以在一定程度上解决因没有统计信息而导致CBO选错执行计划的问题。
12c开始,该特性改名叫做 动态统计信息(Dynamic statistics)
2. 动态采样原理
不同的应用、规则千差万别,oracle如何能判断各列间的关系,较准确地得出基数值?
其实,oracle在生成执行计划前,采样选取了表中部分数据块,对采样的数据块实际执行了一次目标sql,这样就能得到这部分数据块的实际返回结果,而它又能通过数据字典查到表中总数据块数,根据这个比例放大实际执行结果,这个结果就可以作为目标sql较准确的基数值。
因此,只要目标表数据分布相对均匀,oracle就能做到无论各列间有什么关系,都能较准确地估算基数值。
注意,动态采样仅适合单表或多表关联的第一个驱动表的select,update,delete语句。如果对多表使用动态采样,oracle无法判断采样哪些数据块更有代表性,可能导致判断错上加错。
3. 启用方法
启用方法有两种:
- 设置参数 optimizer_dynamic_sampling 的值>=1,10gR2以上版本默认值为2,即默认是开启的。
- 使用动态采样hint:dynamic_sampling(t,level),这里的level对应上面的参数值。
select /*+ dynamic_sampling(t,2) */ * from t where n1=3 and n2=2 and c1='a'
optimizer_dynamic_sampling 参数值含义如下(以下参考自12.1文档):
其中默认采样数据块数由_optimizer_dyn_smp_blks隐含参数控制,默认为32。
Level | 含义 | 默认采样数据块数 (Blocks) |
0 | 不启用 | n/a |
1 | 对没有统计信息且满足以下条件的表启用
| 32 |
2 | 默认值,对没有统计信息的表启用动态采样 | 64 |
3 | 满足以下任意条件时启用:
| 64 |
4 | 满足以下任意条件时启用:
| 64 |
5 | The criteria are identical to level 4, but the database uses a different sample size. | 128 |
6 | The criteria are identical to level 4, but the database uses a different sample size. | 256 |
7 | The criteria are identical to level 4, but the database uses a different sample size. | 512 |
8 | The criteria are identical to level 4, but the database uses a different sample size. | 1024 |
9 | The criteria are identical to level 4, but the database uses a different sample size. | 4086 |
10 | The criteria are identical to level 4, but the database uses a different sample size. | All blocks |
11 | 12c新增等级,在优化器认为oracle需要动态采样数据时自动收集 | Automatically determined |
二、 多列统计信息 MultiColumn Statistics
1. 简介
实际上处理where条件中出现有关联关系的列时不止一种解决方案,11g开始,oracle引入了多列统计信息,也称为组合列统计信息 Column Group Statistics。
11g开始,可以人为指定存在关系的一组列为目标表上的一个组合列,然后使用dbms_stats包对这个组合列收集统计信息,收集到的就是所谓多列统计信息。收集完成后,CBO自然也就知道了组合列的数据分布情况。
2. 使用案例
创建cust_state_province和country_id列的Column Group
DECLARE
cg_name varchar2(30);
BEGIN
cg_name := dbms_stats.create_extended_stats(null,'customers','(cust_state_province,country_id)');
END;
/
查看column group name
select sys.dbms_stats.show_extended_stats_name('sh','customers','(cust_state_province,country_id)') col_group_name from dual;
COL_GROUP_NAME
--------------------------------------------------------------------------------
SYS_STU#S#WF25Z#QAHIHE#MOFFMM_
通过sys.col$基表可以看到,组合列其实就是在该表中多加了一列,列名为column group name,类似oracle的函数索引。可以从dba_stat_extentions视图中查询目标表所有组合列信息。
--查询多列统计信息
Select extension_name, extension from user_stat_extensions where table_name='CUSTOMERS';
EXTENSION_NAME EXTENSION
------------------------------ ----------------------------------------
SYS_STU#S#WF25Z#QAHIHE#MOFFMM_ ("CUST_STATE_PROVINCE","COUNTRY_ID")
--查看distinct数和柱状图使用情况
select e.extension col_group, t.num_distinct, t.histogram
from user_stat_extensions e, user_tab_col_statistics t
where e.extension_name = t.column_name
and e.table_name = t.table_name
and t.table_name = 'CUSTOMERS';
COL_GROUP NUM_DISTINCT HISTOGRAM
---------------------------------------- ------------ ---------------
("CUST_STATE_PROVINCE","COUNTRY_ID") 145 FREQUENCY
收集多列统计信息
--收集已存在的列组统计信息
EXEC DBMS_STATS.GATHER_TABLE_STATS('SH','CUSTOMERS',METHOD_OPT =>'FOR ALL COLUMNS SIZE AUTO');
--收集新指定的列组统计信息
EXEC DBMS_STATS.GATHER_TABLE_STATS('SH','CUSTOMERS',METHOD_OPT =>'FOR ALL COLUMNS SIZE SKEWONLY FOR COLUMNS (CUST_STATE_PROVINCE,COUNTRY_ID) SIZE SKEWONLY');
删除Column Group
exec dbms_stats.drop_extended_stats('sh','customers','(cust_state_province,country_id)');
参考
https://docs.oracle.com/database/121/TGSQL/tgsql_astat.htm#TGSQL453
https://docs.oracle.com/database/121/REFRN/GUID-43655FC3-3C32-486B-8B11-8C20C152618D.htm#REFRN10140