在CBO的IO模式中全表扫描的IO代价不是直接由MBRC(db_file_multiblock_read_count)计算来的而是由一个相应的调整的值(ADJMBRC)计算的
IO=+CEIL(TABBLKS/ADJMBRC)
JonathanLewis曾经讨论过ADJMBRC是由MBRC和数据块大小决定的以k数据块大小为例相应的ADJMBRC是
SQL代码
MBRCADJMBRC
可以看到ADJMBRC是一些ROUND过的值且看起来似乎无规律我们这里做个数字游戏看看这些数字直接是否有没有规律
由之前的公式可知ADJMBRC计算如下
ADJMBRC ≈ TABBLKS/(IO )
我们通过测试调整TABBLKS可以发现ADJMBRC会逐渐接近某个数字以MBRC=为例其ADJMBRC接近为同样可得到其他MBRC的ADJMBRC为
SQL代码
MBRCADJMBRC
虽然精度提高了但是规律还是不可寻我们尝试计算ADJMBRC/MBRC看看会有什么结果
SQL代码
MBRCADJMBRCADJMBRC/MBRC
嗯还是看不到规律不过注意到我们这的MBRC直接是倍数关系那么再试试将ADJMBRC/MBRC的结果前后相除会有什么结果
SQL代码
MBRCADJMBRCADJMBRC/MBRC(ADJMBRC/MBRC[n*])/(ADJMBRC/MBRC[n])
哈这下找到了由上面的推导过程也就不难得出ADJMBRC的公式了
ADJMBRC = /POWER(LOG(MBRC))*MBRC
再考虑BLKSIZ因素上述公式就可以调整为
ADJMBRC = /POWER(LOG(/BLKSIZ*MBRC))*/BLKSIZ*MBRC
对取反可知其为(/)但是我仍然没有看出是如何来的上述公式调整为
ADJMBRC = //POWER(LOG(/BLKSIZ*MBRC))*/BLKSIZ*MBRC
有了上述公式我们就不难通过SQL来估算表(或分区)的Full Table Scan的IO代价了
SQL代码
HELLODBACOM>selectpvaluembrc
//POWER(LOG(/spblock_size*pvalue))*/spblock_size*pvalueadjmbrc
sblocks
+ceil(sblocks/(//POWER(LOG(/spblock_size*pvalue))*/spblock_size*pvalue))IOCOST
fromdba_segmentssdba_tablespacesspall_parametersp
wheresowner=DEMOandssegment_name=T_TEST
andstablespace_name=sptablespace_name
andpname=db_file_multiblock_read_count;
MBRCADJMBRCBLOCKSIOCOST
HELLODBACOM>setautottraceexp
HELLODBACOM>select/*+no_cpu_costing*/*fromdemot_test;
ExecutionPlan
Planhashvalue:
|Id|Operation|Name|Rows|Bytes|Cost|
||SELECTSTATEMENT|||K||
||TABLEACCESSFULL|T_TEST||K||