在CBO的IO模式中全表掃描的IO代價不是直接由MBRC(db_file_multiblock_read_count)計算來的而是由一個相應的調整的值(ADJMBRC)計算的
IO = +CEIL(TABBLKS/ADJMBRC)
Jonathan Lewis曾經討論過ADJMBRC是由MBRC和數據塊大小決定的以k數據塊大小為例相應的ADJMBRC是
SQL代碼
MBRC ADJMBRC
可以看到ADJMBRC是一些ROUND過的值且看起來似乎無規律我們這裡做個數字游戲看看這些數字直接是否有沒有規律
由之前的公式可知ADJMBRC計算如下
ADJMBRC ≈ TABBLKS/(IO )
我們通過測試調整TABBLKS可以發現ADJMBRC會逐漸接近某個數字以MBRC=為例其ADJMBRC接近為同樣可得到其他MBRC的ADJMBRC為
SQL代碼
MBRC ADJMBRC
雖然精度提高了但是規律還是不可尋我們嘗試計算ADJMBRC/MBRC看看會有什麼結果
SQL代碼
MBRC ADJMBRC ADJMBRC/MBRC
嗯還是看不到規律不過注意到我們這的MBRC直接是倍數關系那麼再試試將ADJMBRC/MBRC的結果前後相除會有什麼結果
SQL代碼
MBRC ADJMBRC ADJMBRC/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>select pvalue mbrc
//POWER(LOG(/spblock_size*pvalue))*/spblock_size*pvalue adjmbrc
sblocks
+ceil(sblocks/(//POWER(LOG(/spblock_size*pvalue))*/spblock_size*pvalue)) IOCOST
from dba_segments s dba_tablespaces sp all_parameters p
where sowner=DEMO and ssegment_name = T_TEST
and stablespace_name = sptablespace_name
and pname = db_file_multiblock_read_count;
MBRC ADJMBRC BLOCKS IOCOST
HELLODBACOM>set autot trace exp
HELLODBACOM>select /*+no_cpu_costing*/* from demot_test;
Execution Plan
Plan hash value:
| Id | Operation | Name | Rows | Bytes | Cost |
| | SELECT STATEMENT | | | K| |
| | TABLE ACCESS FULL| T_TEST | | K| |
From:http://tw.wingwit.com/Article/program/Oracle/201311/18524.html