不过有趣的是,这种表级别的动态采样跟session/system和cursor level是不同的。
第一个不同:session/system和cursor level的动态采样不是一定发生的,而是需要满足条件才发生的。
第二个不同:采样的块数也与session/system和cursor level不同。
session/system和cursor level的采样块数前面已经有过表格说明,这里不再给出。我们看下表级别的采样块数,一个简单的公式:
2^(level - 1)*_optimizer_dyn_smp_blks (_optimizer_dyn_smp_blks的默认值为 32)
因此level 1的采样块数为
2^0*32 = 1*32 = 32
level 4的采样块数为
2^3*32 = 8 * 32 = 256
level 9的采样块数为
2^8*32 = 256 * 32 = 8192
level 10再次出现了跳跃,有2的32次方个块,也就是一个表中所有的块。读者可以自己对比下,表级别的采样块数与session/system和cursor level的不同。
这里还需要注意一点,不知道是不是由于BUG,在使用表级的动态采样后,执行计划的输出Note部分并不能真正的显示SQL使用的采样级别,而只是默认显示系统当前的optimizer_dynamic_sampling参数设置的采样级别。
test@DLSP>alter session set events '10053 trace name context forever, level 1';
Session altered.
test@DLSP>select /*+ dynamic_sampling(t,5) */
2 count(*) as cnt
3 from
4 t
5 where
6 attr1 = 19
7 and id>1;
alter session set events '10053 trace name context off';
CNT
----------
0
Execution Plan
----------------------------------------------------------
Plan hash value: 2966233522
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 3536 (1)| 00:00:43 |
| 1 | SORT AGGREGATE | | 1 | 26 | | |
|* 2 | TABLE ACCESS FULL| T | 22 | 572 | 3536 (1)| 00:00:43 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("ATTR1"=19 AND "ID">1)
Note
-----
- dynamic sampling used for this statement (level=2)
test@DLSP>show parameter dy
NAME TYPE VALUE
------------------------------------ ---------------------- ------------------------------
optimizer_dynamic_sampling integer 2
SELECT /* OPT_DYN_SAMP */ /*+ ALL_ROWS IGNORE_WHERE_CLAUSE NO_PARALLEL(SAMPLESUB) opt_param('parallel_execution_enabled', 'false') NO_PARALLEL_INDEX(SAMPLESUB) NO_SQL_TUNE */ NVL(SUM(C1),0), NVL(SUM(C2),0) FROM (SELECT /*+ IGNORE_WHERE_CLAUSE NO_PARALLEL("T") FULL("T") NO_PARALLEL_INDEX("T") */ 1 AS C1, CASE WHEN "T"."ATTR1"=19 AND "T"."ID">1 THEN 1 ELSE 0 END AS C2 FROM "TEST"."T" SAMPLE BLOCK (3.186183 , 1) SEED (1) "T") SAMPLESUB
*** 2014-07-17 16:33:08.779
** Executed dynamic sampling query:
level : 5
sample pct. : 3.186183
actual sample size : 31062
filtered sample card. : 0
orig. card. : 1309984
block cnt. table stat. : 16038
block cnt. for sampling: 16038
max. sample block cnt. : 512
sample block cnt. : 511
min. sel. est. : 0.00050000
** Using dynamic sampling card. : 974897
** Dynamic sampling updated table card.
** Using single table dynamic sel. est. : 0.00002231
Table: T Alias: T
Card: Original: 974896.978474 Rounded: 22 Computed: 21.75 Non Adjusted: 21.75
虽然我说过表级别的动态采样会无条件的被执行,但是采样的结果会被做检查,如果发现不符合要求,采样的结果会被抛弃。
最简单的看到这种现象发生的情况是,构造一个表,分析统计信息,然后SQL中不要任何谓词如:
sys@DLSP>@tabstat
Please enter Name of Table Owner: test
Please enter Table Name : t
**********************************************************
Table Level
**********************************************************
Table Number Empty Chain Average Global Sample Date
Name of Rows Blocks Blocks Count Row Len Stats Size MM-DD-YYYY
------------------------------ -------------- --------------- ------------ -------- ------- ------ -------------- ----------
T 1,000,000 160,38 0 0 109 YES 1,000,000 07-17-2014
Column Distinct Number Number Sample Date
Name Values Density Buckets Nulls Size MM-DD-YYYY
------------------------------ ------------ ----------- ------- ------------ -------------- ----------
ID 1,000,000 .00000100 1 0 1,000,000 07-17-2014
ATTR1 10 .10000000 1 0 1,000,000 07-17-2014
FILLER 1 1.00000000 1 0 1,000,000 07-17-2014
alter session set events '10053 trace name context forever, level 1';
select /*+ DYNAMIC_SAMPLING(t 4) */
count(*) as cnt
from
t;
CNT
----------
1000000
1 row selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 2966233522
-------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3531 (1)| 00:00:43 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| T | 1000K| 3531 (1)| 00:00:43 |
-------------------------------------------------------------------
alter session set events '10053 trace name context off';
好像是动态采样没有发生,但是事实不是这样的,由于是表级别的动态采样,所以一定会发生,会无条件的发生!我们看下trace文件的信息:
** Generated dynamic sampling query:
query text :
SELECT /* OPT_DYN_SAMP */ /*+ ALL_ROWS IGNORE_WHERE_CLAUSE NO_PARALLEL(SAMPLESUB) opt_param('parallel_execution_enabled', 'false') NO_PARALLEL_INDEX(SAMPLESUB) NO_SQL_TUNE */ NVL(SUM(C1),0), NVL(SUM(C2),0) FROM (SELECT /*+ NO_PARALLEL("T") FULL("T") NO_PARALLEL_INDEX("T") */ 1 AS C1, 1 AS C2 FROM "TEST"."T" SAMPLE BLOCK (1.589974 , 1) SEED (1) "T") SAMPLESUB
*** 2014-07-17 13:56:08.564
** Executed dynamic sampling query:
level : 4
sample pct. : 1.589974
actual sample size : 4159
filtered sample card. : 4159
orig. card. : 1000000
block cnt. table stat. : 16038
block cnt. for sampling: 16038
max. sample block cnt. : 256
sample block cnt. : 255
min. sel. est. : -1.00000000
** Not using dynamic sampling for single table sel. or cardinality.
请注意跟踪文件里的输出,确实做了块采样,采样的块数为255,但是块采样的结果并没有被采纳。
还可以举出一些其他案例,例如,动态采样在处理一些表中极小的结果集的时候可能会存在一些异常,这些异常可能会导致非常不准确的基数估计或者动态采样的结果不被采用。
select distinct attr1 from t;
ATTR1
----------
1
6
2
4
5
8
3
7
9
10
begin
dbms_stats.gather_table_stats(ownname =>'test',
tabname => 't',
no_invalidate => FALSE,
estimate_percent => 100,
force => true,
degree => 5,
method_opt => 'for columns attr1 size 254',
cascade => true);
end;
/
收集了直方图
alter session set optimizer_dynamic_sampling=4;
alter session set events '10053 trace name context forever, level 1';
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/22034023/viewspace-1221265/ ,如需转载,请注明出处,否则将追究法律责任。