ITPub博客

首页 > 数据库 > 数据库开发技术 > selectivity issues中deadly defaults对优化器的影响

selectivity issues中deadly defaults对优化器的影响

原创 数据库开发技术 作者:newcomer1981 时间:2009-09-29 14:42:16 0 删除 编辑
cost base fundamentals:selectivity issues中deadly defaults对优化器的影响

验证《cost base fundamentals》第六章节selectivity issues中deadly defaults对优化器的影响。
deadly defaults指致命的默认值,如order表中的date的default值设置为"9999-12-31",造成数据人为的严重不均衡。
测试平台:
OS:Red Hat Enterprise Linux Server release 5.3 (Tikanga)
DB:Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Prod

创建表t9,id列生成数据1,2……2000000,左边以‘0’补齐18位。
建立索引t9。
create table t9 (id char(18),name varchar2(100));
create sequence t1_seq;
begin
for i in 1..2000000 loop
insert into t9
select lpad(to_char(t1_seq.nextval),18,'0'),to_char(t1_seq.nextval)
from dual;
end loop;
end;
commit;

create index t9_id on t9(id);

一、数据分布均匀

收集统计信息。

begin
dbms_stats.gather_schema_stats(ownname => 'MEISHD',estimate_percent => 100);
end;

统计信息如下:
user_tab_col_statistics.id.low_value='000000000000000001'
user_tab_col_statistics.id.high_value='000000000002000000'
user_tab_col_statistics.id.num_distinct=2000000
user_indexes.t9_id.blevel=2
user_indexes.t9_id.leaf_blocks=8369
user_indexes.t9_id.clustering_factor=8683

计算IO_COST为88

index_selectivity = required range / total range + 1/num_distinct + 1/num_distinct
= (70000-60000)/(2000000-1)+2/2000000
= 0.005001

table_selectivity = index_selectivity = 0.005001

cost=blevel + ceiling(leaf_blocks * index_selectivity) + ceiling(clustering_factor * table_selectivity)
=2+ceiling(8369*0.005001)+ceiling(8683*0.005001)
=2+ceiling(41.85)+ceiling(43.42)
=2+42+44
=88

确认IO_COST为88,总COST为88,CPU_COST为0.46。
这里有个疑问,为什么CPU_COST没有统计进去,不知道是因为太小而忽律不计,还是因为disable CPU_COST了(我已经收集了系统信息,应该已经enable CPU_COST了)。

SQL> select * from t9 where id between '000000000000060000' and '000000000000070000';

Execution Plan
----------------------------------------------------------
Plan hash value: 3577433401

-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10002 | 253K| 88 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T9 | 10002 | 253K| 88 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T9_ID | 10002 | | 44 (0)| 00:00:01 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("ID">='000000000000060000' AND "ID"<='000000000000070000')

SQL>


SQL> select a.OPTIONS,a.OBJECT_NAME,a.ID,a.COST,a.CPU_COST,a.IO_COST from v$sql_plan a where plan_hash_value='3577433401';

OPTIONS OBJECT_NAME ID COST CPU_COST IO_COST
-------------------- --------------- ---------- ---------- ---------- ----------
0 88
BY INDEX ROWID T9 1 88 4327797 88
RANGE SCAN T9_ID 2 44 2313943 44

SQL> select pname,pval1 from sys.aux_stats$ where sname='SYSSTATS_MAIN' and pname in ('CPUSPEED','SREADTIM');

PNAME PVAL1
------------------------------ ----------
CPUSPEED 1468
SREADTIM 6.39


CPU_COST=(v$sql_plan.CPU_COST/CPUSPEED)/SREADTIM
=(4327797/1486*1000000)/(6.39/1000)
=0.46


二、数据分布不均匀

如将order表中的date的default值设置为"9999-12-31",这里通过将id修改模拟。

update t9 set id='100000000000000000'where id='000000000002000000';
commit;

收集统计信息:
begin
dbms_stats.gather_schema_stats(ownname => 'MEISHD',estimate_percent => 100);
end;

统计信息如下:
user_tab_col_statistics.id.low_value='000000000000000001'
user_tab_col_statistics.id.high_value='100000000000000000'
user_tab_col_statistics.id.num_distinct=2000000
user_indexes.t9_id.blevel=2
user_indexes.t9_id.leaf_blocks=8369
user_indexes.t9_id.clustering_factor=8683

计算IO_COST为4

index_selectivity = required range / total range + 1/num_distinct + 1/num_distinct
= (70000-60000)/(100000000000000000-1)+2/2000000
= 0.000001

cost=blevel + ceiling(leaf_blocks * index_selectivity) + ceiling(clustering_factor * table_selectivity)
=2+ceiling(8369*0.000001)+ceiling(8683*0.000001)
=2+ceiling(0.008369)+ceiling(0.008683)
=2+1+1
=4

确认IO_COST为4,总COST为4,CPU_COST为0.00308。
关于CPU_COST的疑问同上。

SQL> select * from t9 where id between '000000000000060000' and '000000000000070000';

Execution Plan
----------------------------------------------------------
Plan hash value: 3577433401

-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T9 | 1 | 26 | 4 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T9_ID | 1 | | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("ID">='000000000000060000' AND "ID"<='000000000000070000')

SQL>

SQL> select a.OPTIONS,a.OBJECT_NAME,a.ID,a.COST,a.CPU_COST,a.IO_COST from v$sql_plan a where plan_hash_value='3577433401';

OPTIONS OBJECT_NAME ID COST CPU_COST IO_COST
-------------------- --------------- ---------- ---------- ---------- ----------
0 4
BY INDEX ROWID T9 1 4 29226 4
RANGE SCAN T9_ID 2 3 21764 3

CPU_COST=(v$sql_plan.CPU_COST/CPUSPEED)/SREADTIM
=(29226/1486*1000000)/(6.39/1000)
=0.00308

三、数据分布不均匀,收集了histogram statistics

收集histogram statistics
begin
dbms_stats.gather_table_stats(ownname => 'MEISHD',tabname => 'T9',estimate_percent => 100,method_opt => 'FOR COLUMNS SIZE 20 id');
end;
SQL> select table_name,column_name,num_buckets,histogram from user_tab_col_statistics where column_name='ID';

TABLE_NAME COLUMN_NAME NUM_BUCKETS HISTOGRAM
------------------------------ ------------------------------ ----------- ---------------
T9 ID 20 HEIGHT BALANCED

SQL> select endpoint_number,endpoint_actual_value from user_tab_histograms where table_name='T9' and column_name='ID';

ENDPOINT_NUMBER ENDPOINT_ACTUAL_VALUE
--------------- ------------------------------
0 000000000000000001
1 000000000000100000
2 000000000000200000
3 000000000000300000
4 000000000000400000
5 000000000000500000
6 000000000000600000
7 000000000000700000
8 000000000000800000
9 000000000000900000
10 000000000001000000
11 000000000001100000
12 000000000001200000
13 000000000001300000
14 000000000001400000
15 000000000001500000
16 000000000001600000
17 000000000001700000
18 000000000001800000
19 000000000001900000
20 100000000000000000

21 rows selected.

SQL>

计算IO_COST为88

index_selectivity_bucket = required range / total range + 1/num_distinct + 1/num_distinct)
= (70000-60000)/(100000-1)+2/2000000
= 0.100002
index_selectivity = index_selectivity_bucket/num_buckets = 0.0050001


cost=blevel + ceiling(leaf_blocks * index_selectivity) + ceiling(clustering_factor * table_selectivity)
=2+ceiling(8369*0.0050001)+ceiling(8683*0.0050001)
=2+ceiling(41.84)+ceiling(43.42)
=2+42+44
=88

SQL> select * from t9 where id between '000000000000060000' and '000000000000070000';

Execution Plan
----------------------------------------------------------
Plan hash value: 3577433401

-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10000 | 253K| 88 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T9 | 10000 | 253K| 88 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T9_ID | 10000 | | 44 (0)| 00:00:01 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("ID">='000000000000060000' AND "ID"<='000000000000070000')

SQL>

确认IO_COST为88,总COST为88,CPU_COST为0.46。
关于CPU_COST的疑问同上。

SQL> select a.OPTIONS,a.OBJECT_NAME,a.ID,a.COST,a.CPU_COST,a.IO_COST from v$sql_plan a where plan_hash_value='3577433401';

OPTIONS OBJECT_NAME ID COST CPU_COST IO_COST
-------------------- --------------- ---------- ---------- ---------- ----------
0 88
BY INDEX ROWID T9 1 88 4327057 88
RANGE SCAN T9_ID 2 44 2313543 44

CPU_COST=(v$sql_plan.CPU_COST/CPUSPEED)/SREADTIM
=(4327057/1486*1000000)/(6.39/1000)
=0.46

总结
在数据分布严重不均衡的情况下(尤其是认为设置了致命的default值),根据统计信息算出的COST严重不符事实。因此:
1、设置default值时,应在正常的数据范围内;
2、如果数据自身很不均衡,则需要通过收集histogram统计信息来保证COST的准确性。
[@more@]

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/22504389/viewspace-1027476/ ,如需转载,请注明出处,否则将追究法律责任。

上一篇: 没有了~
下一篇: 没有了~
请登录后发表评论 登录
全部评论

注册时间:2009-12-03

  • 博文量
    1
  • 访问量
    5332