全表扫描计算成本

SQL> select * from v$version where rownum=1;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production

创建手动管理的表空间,blockssize 8k

 create tablespace test datafile
'/oradata/june/test.dbf' size 50m autoextend on maxsize 200m
uniform size 1m segment space management manual blocksize 8k; 

创建测试用户test,默认表空间 test

SQL> create user test identified by oracle default tablespace test;

create table test as select * from dba_objects where 1=0 ;


alter table test pctfree 99 pctused 1;


pctfree 保留空间 用于update

SQL> insert into test select * from dba_objects where rownum<2;

1 row created.

SQL> commit;

Commit complete.

alter table test minimize records_per_block;

SQL> insert into test select * from dba_objects where rownum<1000;

999 rows created.

SQL> commit;

Commit complete.

现在使用了1000个块

 BEGIN
DBMS_STATS.GATHER_TABLE_STATS(ownname => 'TEST',
tabname => 'TEST',
estimate_percent => 100,
method_opt => 'for all columns size 1',
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				     1000

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

COUNT(DISTINCTDBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID))
---------------------------------------------------
					       1000

SQL> alter system set db_file_multiblock_read_count=16;

System altered.


SQL> select count(*) from test;


Execution Plan
----------------------------------------------------------
Plan hash value: 1950795681

-------------------------------------------------------------------
| Id  | Operation	   | Name | Rows  | Cost (%CPU)| Time	  |
-------------------------------------------------------------------
|   0 | SELECT STATEMENT   |	  |	1 |   220   (0)| 00:00:03 |
|   1 |  SORT AGGREGATE    |	  |	1 |	       |	  |
|   2 |   TABLE ACCESS FULL| TEST |  1000 |   220   (0)| 00:00:03 |
-------------------------------------------------------------------


Statistics
----------------------------------------------------------
	  1  recursive calls
	  0  db block gets
       1003  consistent gets
	 79  physical reads
	  0  redo size
	422  bytes sent via SQL*Net to client
	420  bytes received via SQL*Net from client
	  2  SQL*Net roundtrips to/from client
	  0  sorts (memory)
	  0  sorts (disk)
	  1  rows processed


COST=220



全表扫描成本计算公式:

成本的计算方式如下:
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 =1000/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 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"
  from dual;  2    3    4  

  sreadtim
----------
	12

单块读耗时12毫秒


操作系统CPU 和磁盘信息Oracle都可以获取到

CPUCycles 等于 PLAN_TABLE里面的CPU_COST---这个ORACLE未解密,无法知道怎么计算的
SQL> explain plan for select count(*) from test;

Explained.

SQL> select cpu_cost from plan_table;

  CPU_COST
----------
   7271440

cpuspeed 等于 CPUSPEEDNW= 2696.05568
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.



成本的计算方式如下:
Cost = (
       #SRds * sreadtim +
       #MRds * mreadtim +
       CPUCycles / cpuspeed
       ) / sreadtime

#SRds * sreadtim =0 单块读次数为0

#SRds * sreadtim=(number of single block reads 单块读次数) * 12


#MRds * mreadtim =(number of multi block reads) * 42=1000/16 * 42=2625
CPUCycles / cpuspeed=7271440/2696.05568=2697/1000=2.697  ---每秒转换为每毫秒/1000


sreadtime=12


那么COST=1000/16*42/12+7271440/2696.05568/12/1000

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

CEIL(1000/16*42/12+7271440/2696.05568/12/1000)
----------------------------------------------
                                           219


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次数

原文地址:https://www.cnblogs.com/zhaoyangjian724/p/3797881.html