oracle 11.2.0.3全表掃描COST計算(非工作量模式)

drop table test purge;

 

create table test as selectfrom dba_objects;

 

--蒐集統計信息,不蒐集直方圖信息

BEGIN

DBMS_STATS.GATHER_TABLE_STATS(ownname =>'SCOTT',

tabname => 'TEST',

estimate_percent => 100,

method_opt => 'for all columns size 1',

degree =>DBMS_STATS.AUTO_DEGREE,

cascade=>TRUE

);

END;

/

select owner,blocks from dba_tables where owner='SCOTT' and table_name='TEST';


注意:如果沒有收集過系統統計信息,那麼Oracle採用非工作量統計,如果收集了,Oracle採用工作量統計的計算方法

 

Cost= (
       #SRds * sreadtim+                           ---SRds=0  (全表掃描沒有單塊讀)
       #MRds * mreadtim+                         ---MRds=BLOCKS/MBCR=1105/128, mreadtim=266
       CPUCycles / cpuspeed /1000        ---CPUCycles=PLAN_TABLE.CPU_COST,cpuspeed=2500
       ) / sreadtime

 

所以人工計算的成本等於:

 
#SRds – number of single block reads 單塊讀個數
#MRds – number of multi block reads 
多塊讀個數
#CPUCyles – number of CPU cycles     CPU
時鐘週期數

sreadtim – single block read time  單塊讀耗時(單位milliseconds毫秒,1000毫秒等於1)
mreadtim – multi block read time  
多塊讀耗時(單位milliseconds毫秒,1000毫秒等於1)
cpuspeed – CPU cycles per second     CPU
頻率(單位MHZ)
mreadtim=ioseektim+db_file_multiblock_count*db_block_size/iotftspeed
sreadtim=ioseektim+db_block_size/iotfrspeed
CPUCycles
等於PLAN_TABLE裏面的CPU_COST—這個ORACLE未解密,無法知道怎麼計算的

Cost= (
       #SRds * sreadtim+                           ---SRds=0
       #MRds * mreadtim+                         ---MRds=BLOCKS/MBCR=10003/12, mreadtim=30
       CPUCycles / cpuspeed /1000        ---CPUCycles=PLAN_TABLE.CPU_COST,cpuspeed=19215491
       ) / sreadtime

 

我這裏因爲MBRC 爲0,所以CBO採用了非工作量(noworkload)來計算成本

#SRds=0,因爲是全表掃描,單塊讀爲0

#MRds=表的塊數/多塊讀參數=1105/128

mreadtim=ioseektim+db_file_multiblock_count*db_block_size/iotftspeed

 

select (select pval1 from sys.aux_stats$where pname = 'IOSEEKTIM') +

        (select value

         from v$parameter

        where name = 'db_file_multiblock_read_count') *

      (select value from v$parameter where name = 'db_block_size') /

      (select pval1 from sys.aux_stats$ where pname = 'IOTFRSPEED')"mreadtim"

from dual;

 

sreadtim=ioseektim+db_block_size/iotfrspeed

 

select (select pval1 from sys.aux_stats$where pname = 'IOSEEKTIM') +

      (select value from v$parameter where name = 'db_block_size') /

      (select pval1 from sys.aux_stats$ where pname = 'IOTFRSPEED')"sreadtim"

  fromdual;

 

CPUCycles 等於 PLAN_TABLE裏面的CPU_COST

 

explain plan for select count(*) from test;

select cpu_cost from plan_table;


cpuspeed 等於 CPUSPEEDNW= 1194

 

那麼整個COST公式代入值計算爲:

select ceil((1105/128*266+19215491/1194/1000)/12from dual;

select count(*) from test;

手工計算出來的COST用四捨五入等於193,和我們看到的194有差別,這是由於隱含參數_tablescan_cost_plus_one參數造成的

 

Set pagesize 500 linesize 500

Col name for a30

Col value for a30

Col describ for a60

SELECT x.ksppinm NAME, y.ksppstvl VALUE,x.ksppdesc describ

 FROMx$ksppi x, x$ksppcv y

 WHERE x.inst_id = USERENV ('Instance')

  AND y.inst_id = USERENV ('Instance')

  AND x.indx = y.indx

  AND x.ksppinm LIKE '%_table_scan_cost_plus_one%';


根據該參數的描述,在table full scanindex fast full scan的時候會將cost+1

那麼我把改參數禁止了試一試

這次得到的Cost等於193,與計算值正好匹配,現在更改db_file_multiblock_read_count參數

 

select ceil(1105/16*42/12+19215491/1194/12/1000from dual;

和實際中執行計劃的COST值一致

 

總結:在非工作量模式下,db_file_multiblock_read_count會影響全表掃描表的COST,11gR2中,全表掃描計算Cost的方式依然和9i/10g一樣,沒有變化。

 

BEGIN 

DBMS_STATS.GATHER_TABLE_STATS(ownname =>'TEST', 

tabname => 'TEST', 

estimate_percent => 100, 

method_opt => 'for all columns size1', 

degree => DBMS_STATS.AUTO_DEGREE, 

cascade=>TRUE 

); 

END; 

 

SQL> select owner,blocks from dba_tables where owner='TEST' and table_name='TEST'; 

 

OWNER                              BLOCKS 

---------------------------------------- 

TEST                                32910 

 

SQL> select count(distinct dbms_rowid.rowid_block_number(rowid)) from test; 

 

COUNT(DISTINCTDBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)) 

--------------------------------------------------- 

                                             23563 

 

 

 

SQL> show parameter multi 

 

NAME                                 TYPE        VALUE 

----------------------------------------------- ------------------------------ 

db_file_multiblock_read_count        integer     16 

parallel_adaptive_multi_user         boolean     TRUE 

 

 

SQL> explain plan for select * from test where owner='SYS'; 

 

已解釋。 

 

SQL> select * from table(dbms_xplan.display()); 

 

PLAN_TABLE_OUTPUT 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

 

----------------------- 

Plan hash value: 1357081020 

 

-------------------------------------------------------------------------- 

| Id | Operation         | Name |Rows  | Bytes | Cost (%CPU)| Time     | 

-------------------------------------------------------------------------- 

|   0| SELECT STATEMENT  |      | 77444 | 7336K|  7223   (1)| 00:01:27 | 

|*  1|  TABLE ACCESS FULL| TEST | 77444 |  7336K| 7223   (1)| 00:01:27 | 

-------------------------------------------------------------------------- 

 

Predicate Information (identified byoperation id): 

--------------------------------------------------- 

 

   1- filter("OWNER"='SYS') 

 

已選擇13行 

 

 

COST=7223 

 

 

 select count(*) from test where owner='SYS'; 

 --986880 

 

 

 

全表掃描成本計算公式: 

 

成本的計算方式如下: 

Cost = (#SRds * sreadtim + #MRds * mreadtim+ CPUCycles / cpuspeed) / sreadtime 

 

#SRds - number of single block reads 單塊讀次數 

 

#MRds - number of multi block reads  多塊讀次數 

 

#CPUCyles - number of CPU cycles     CPU時鐘週期數 

 

sreadtim - single block read time    一次單塊讀耗時(單位milliseconds毫秒,1000毫秒等於1秒) 

 

mreadtim - multi block read time     一次多塊讀耗時(單位milliseconds毫秒,1000毫秒等於1秒) 

 

cpuspeed - CPU cycles per second     CPU頻率(單位MHZ)--每秒鐘CPU做多少個輪訓 

 

 

全表掃描多塊讀那麼#SRds=0 

 

#MRds=16,每次I/O讀16個塊 

 

mreadtim =32910/16 

 

SQL> select pname, pval1 from sys.aux_stats$ where sname='SYSSTATS_MAIN'; 

 

PNAME                   PVAL1 

---------------------------------------- 

CPUSPEED 

CPUSPEEDNW             2696.05568 

IOSEEKTIM                  10 

IOTFRSPEED               4096 

MAXTHR 

MBRC 

MREADTIM 

SLAVETHR 

SREADTIM 

 

9 rows selected. 

 

這裏因爲MBRC 爲0,所以CBO採用了非工作量(noworkload)來計算成本,所有的系統全是用的 非工作量。 

 

計算mreadtim - multi block read time    一次多塊讀耗時(單位milliseconds 毫秒,1000毫秒等於1秒) 

 

mreadtim=ioseektim+db_file_multiblock_count*db_block_size/iotftspeed 

 

ioseektim:尋道尋址的時間 

 

db_file_multiblock_count*db_block_size=16*8K=128K---一次I/O的數據量 

 

 

db_file_multiblock_count*db_block_size/iotftspeed=多塊讀耗時時間 

 

 

iotftspeed:I/O傳輸速度 

 

mreadtim(多塊讀耗時)=尋道尋址的時間+多塊讀耗時 

SQL> select (select pval1 from sys.aux_stats$ where pname = 'IOSEEKTIM') + 

      (select value 

         from v$parameter 

        where name = 'db_file_multiblock_read_count') * 

      (select value from v$parameter where name = 'db_block_size') / 

      (select pval1 from sys.aux_stats$ where pname = 'IOTFRSPEED')"mreadtim" 

 from dual;  2    3   4    5    6   7   

 

 mreadtim 

---------- 

   42 

 

多塊讀的耗時有42毫秒 

 

sreadtim(單塊讀耗時)=ioseektim+db_block_size/iotfrspeed 

 

SQL> select (select pval1 fromsys.aux_stats$ where pname = 'IOSEEKTIM') + 

      (select value from v$parameter where name = 'db_block_size') / 

      (select pval1 from sys.aux_stats$ where pname = 'IOTFRSPEED') "sreadtim" 

 from dual;  2    3   4   

 

 sreadtim 

---------- 

   12 

 

單塊讀耗時12毫秒 

 

 

操作系統CPU 和磁盤信息Oracle都可以獲取到 

 

CPUCycles 等於 PLAN_TABLE裏面的CPU_COST---這個ORACLE未解密,無法知道怎麼計算的 

 

 

 

SQL> explain plan for select  * from test where owner='SYS'; 

 

已解釋。 

 

SQL> select cpu_cost fromplan_table;           

 

 CPU_COST 

---------- 

 720716510 

 720716510 

 

cpuspeed 等於 CPUSPEEDNW=2696.05568 

SQL> select pname, pval1 fromsys.aux_stats$ where sname='SYSSTATS_MAIN'; 

 

PNAME                   PVAL1 

---------------------------------------- 

CPUSPEED 

CPUSPEEDNW             2696.05568 

IOSEEKTIM                  10 

IOTFRSPEED               4096 

MAXTHR 

MBRC 

MREADTIM 

SLAVETHR 

SREADTIM 

 

9 rows selected. 

 

 

 

成本的計算方式如下: 

Cost = ( 

      #SRds * sreadtim + 

      #MRds * mreadtim + 

      CPUCycles / cpuspeed 

      ) / sreadtime 

 

#SRds * sreadtim =0 單塊讀次數爲0 

 

#SRds * sreadtim=(number of single blockreads 單塊讀次數) * 12 

 

 

#MRds * mreadtim =(number of multi blockreads) * 42=32910/16 * 42=86388.75 

 

 

sreadtime=12 

 

 

SQL> select ceil(32910/16*42/12 +  720716510/2696.05568/1000/12) from dual; 

 

CEIL(32910/16*42/12+720716510/2696.05568/1000/12) 

------------------------------------------------- 

                                            7222 

 

 

Cost = ( 

            #MRds * mreadtim + 

      CPUCycles / cpuspeed 

      ) / sreadtime 

 

 

Cost =  

            #MRds  +( 

      CPUCycles / cpuspeed 

      ) / sreadtime 

 

 

最終的成本計算公式=Cost = #MRds (忽略CPU的情況下,就是多塊讀的次數=1000/16) 

 

說明減少物理 io掃描次數,SQL優化的核心思想

 

Cost =       #MRds * mreadtim/ sreadtime 

 

#MRds - number of multi block reads  多塊讀I/O次數  

發佈了19 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章