oracle包含的2种代价模型:

oracle通过隐含参数“_optimizer_cost_model"控制使用哪种代价模型

1io代价模型

cost=iocost

2cpu代价模型

cost=iocost+cpucost

在代价转换的过程中,所有的代价都转换为单数据块读的单次代价

存在四种类型的io,单块读,多块读,直接数据块读和直接数据块写

iocost=上述四种io的消耗

选择率与密度,空值,唯一值,以及柱状图数据有关。过滤条件的选择率

a and b a的选择率*b的选择率

a or b a的选择率+b的选择率-a*b

not a 1-a的选择率

在未引入系统统计信息之前,oracle会假设下面的2中情况是成立的:

1 单块读的平均消耗时间和多块读的平均消耗时间相等

2全表扫的时候,根据下面的情况计算全表扫描的成本

mbdivisor=1.675*power(db_file_multiblock_read_count,0.6581)

tsc=blocks/mbdivisor

10.2中的mbdivisor大约是4.4,11.2中的改值大约是3.6

cpu cost model在开启的情况下,全表扫描的计算公式如下:

tsc cost=i/o cost+cpu cost

i/o cost =1+ceil(blocks/mbrc)*(mreadtim/sreadtim)

cpu cost=round(#cpucycles/cpuspeed/1000/sreadtim)

系统的统计信息放在了aux_stats$中

查看统计信息收集的历史

wri$_optstat_tab_history

执行计划中的记录数是数据记录数*选择率,运行时间的估算,总的单数据块读的io代价*单次数据块读时间

全表扫描的大概估计:

索引范围扫描:分支节点读取的数据块数和叶子节点数据块数决定。分支节点数据块的读取数等于索引数的分支节点层数。叶子节点的计算是叶子节点数*条件选择率

所以索引的代价大概是层数+叶结点数*选择率*optimizer_index_cost_adj

索引rowid访问表的计算:这边涉及到一个聚簇因子,它是代表了数据块的聚集性。

iocost=索引树高度+叶子数据块数量*access的选择率+聚簇因子*filter的选择率*optica/100


索引范围扫描的计算公式:

i/o cost= index access i/o cost + table access i/o cost

index access i/o cost= blevel+ceil(#leaf_block*ix_sel)

table acess i/o cost=ceil(clustering_factor*ix_sel_with_filters)


列上没有直方图,且没有null值得情况下,列的选择率=(1/num_distinct)

列上没有直方图,且有null值的情况下,列的选择率=(1/num_distinct)*((num_rows-num_nulls)/num_rows)

列上的low_value和high_value是用来评估列做范围查询时的可选择率

目标列大于指定值val,且val处于low_value与high_value之间

selectivity=((high_value-val)/(high_value-low_value)*null_adjust;

null_adjust=(num_rows-num_nulls)/num_rows

目标列小于指定val,且val处于low和high之间

selectivity=(val-low_value)/(high_value-low_value)*null_adjust;

null_adjust=(num_rows-num_nulls)/num_rows

目标列大于或等于指定值val,且val处于low和high之间

selectivity=((high-val)/(high-low)+1/num_distinct)*null_adjust

目标列小于或等于指定值val,且val处于low和high之间

selectivity=((val-low)/high-low)+1/num_distinct)*null_adjust

目标列在指定值val1和val2之间,且val1和val2都在low和high之间

selectivity=((val2-val1)/high-low)+2/num_distinct)*null_adjust

对于使用了绑定变量的sql,启动绑定变量窥探,则对于>的范围查询

Selectivity = (high_value - limit) / (high_value - low_value)  limit是绑定变量的值

Cardinality = rows*selectivity

对于使用了绑定变量的sql,如果没有启用绑定变量窥探,则对于>的范围查询

selectivity=0.05

没有启用绑定变量窥探,对于between and的查询

selectivity=0.0025



--测试选择率

SQL> select count(*) from tt where object_id is null;

  COUNT(*)
----------
        99

SQL> select count(*) from tt;

  COUNT(*)
----------
     49859

 exec dbms_stats.gather_table_stats(ownname => 'baixyu',tabname => 'TT',method_opt => 'for all columns size 1');

SQL> select count(*) from tt where object_id is null;


  COUNT(*)
----------
        99


SQL> select count(*) from tt;


  COUNT(*)
----------
     49859

 select num_distinct,low_value,high_value,num_nulls from user_tab_col_statistics s where s.table_name='TT' and s.column_name='OBJECT_ID';


49760 C2020BC3061C2299



SQL> select * from tt where object_id=120;




执行计划
----------------------------------------------------------
Plan hash value: 264906180


--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |    93 |   159   (2)| 00:00:02 |
|*  1 |  TABLE ACCESS FULL| TT   |     1 |    93 |   159   (2)| 00:00:02 |
--------------------------------------------------------------------------


SQL> select 1/49760*((49859-99)/49859)*49859 from dual;


1/49760*((49859-99)/49859)*49859
--------------------------------
                               1

SQL> select * from tt where object_id>120 and object_id<200;


已选择78行。




执行计划
----------------------------------------------------------
Plan hash value: 264906180


--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |    76 |  7068 |   159   (2)| 00:00:02 |
|*  1 |  TABLE ACCESS FULL| TT   |    76 |  7068 |   159   (2)| 00:00:02 |
--------------------------------------------------------------------------


select  (((200-120)/(52744-101)+2/49760)*49760/49859)*49859 from dual;

(((200-120)/(52744-101)+2/49760)*49760/49859)*49859
---------------------------------------------------
                                         77.6187907


在列上没有直方图的情况下,统计信息中的density可以认为是1/num_distinct,在列上有等频直方图时,density的计算公式为

density=1/(2*num_rows*null_adjust)

null_adjust-(num_rows-num_nulls)/num_rows

如果查询条件的输入值等于目标列的某个bucket的endpoint_value那么 列的cardinality的计算公式是

cardinality=num_rows*selectivity

selectivity=bucketsize/num_rows

bucketsize=current_endpoint_number-previous_endpoint_number

如果查询条件的输入值不等于目标列的任意一个bucket的endpoint_value,计算公式如下

cardinality=num_rows*selectivity

selectivity=min(bucketsize)/(2*num_rows)

bucketsize=current_endpoint_number-previous_endpoint_number;

---怎么不直接设置成0?

当列上的直方图信息是等高直方图的时候,等值查询的估算是

1如果查询条件输入值是popular value

cardinality=num_rows*selectivity

selectivity=(buckets_this_popular_value/buckets_totoal)*null_adjust

null_adjust=(num_rows-num_nulls)/num_rows

2如果是unpopular value

分成三种情况。。。。