一准备工作
1.1 取tracefile的几种办法(11g):
select tracefile ,s.module from v$process p,v$session s where s.paddr=p.addr and s.username='TEST' and module ='SQL*Plus'
SELECT value FROM v$diag_info WHERE name='Default Trace File';
2 生成10053
alter session set events '10053 trace name context forever';
exec dbms_system.set_ev(sid,serial#,10053,8,'test');
或者通过sql_Idexecute DBMS_SQLDIAG.DUMP_TRACE(p_sql_id=>'5s4ny8pxtdkyf', p_child_number=>0, p_component=>'Optimizer', p_file_id=>'SQL_TRACE_10053');
3 执行sql,关闭trace
select * from T_KINGDEE_CONSUME_DAY;
alter session set events '10053 trace name context off';
二 解析
oracle成本的计算公式如下:
Cost = (
#SRds sreadtim +
#MRds mreadtim +
CPUCycles / cpuspeed
) / sreadtime
简化为:
cost=#srds + #mrds * mreadtim/sreadtim + #cpucycles/(cpuspped*sreadtim)
#SRds - number of single block reads 单块读的次数
#MRds - number of multi block reads 多块读的次数
#CPUCyles - number of CPU cycles 一个CPU周期
sreadtim - single block read time 读取单个数据块的平均时间
mreadtim - multi block read time 读取多个数据块的平均时间
cpuspeed - CPU cycles per second CPU周期/秒
数据来源:
来源:
select * from sys.aux_stats$
参数解释
FLAGS:标志
CPUSPEEDNW:非工作量统计模式下CPU主频,直接来自硬件
IOSEEKTIM:IO寻址时间(毫秒),直接来自硬件
IOTFRSPEED:IO传输速率(字节/毫秒)
SREADTIM:读取单个数据块的平均时间
MREADTIM:读取多个数据块的平均时间
CPUSPEED:工作量统计模式下CPU主频,根据当前工作量评估出一个合理值
MBRC:oracle收集完统计信息后评估出的一次多块读可以读几个数据块,不设置值其为8
MAXTHR:最大IO吞吐量(字节/秒)
SLAVETHR:平均IO吞吐量(字节/秒)
查看trace文件部分:
SYSTEM STATISTICS INFORMATION
Using NOWORKLOAD Stats
CPUSPEEDNW: 3074 millions instructions/sec (default is 100)
IOTFRSPEED: 4096 bytes per millisecond (default is 4096)
IOSEEKTIM: 10 milliseconds (default is 10)
MBRC: NO VALUE blocks (default is 8)
MBRC:这里在11g里安装完成后不设置显示为128,但在做10053发现其还是为8;
我这里计算为:
sreadtim=ioseektim+db_block_size/IOTFRSPEED=10+8192/4096=12
mreadtim=ioseektim+mbrc*db_block_size/IOTFRSPEED=10+8*8/4=26
查看trace文件:
BASE STATISTICAL INFORMATION
Table Stats::
Table: T_KINGDEE_CONSUME_DAY Alias: T_KINGDEE_CONSUME_DAY
#Rows: 377547 #Blks: 2656 AvgRowLen: 40.00 ChainCnt: 0.00
Index Stats::
Index: IX_KINGDEE_CONSUME_DAY_N1 Col#: 2
LVLS: 2 #LB: 3743 #DK: 951 LB/K: 3.00 DB/K: 397.00 CLUF: 377547.00
Index: PK_T_KINGDEE_CONSUME_DAY Col#: 1 2
LVLS: 2 #LB: 2228 #DK: 377547 LB/K: 1.00 DB/K: 1.00 CLUF: 2979.00
Access path analysis for T_KINGDEE_CONSUME_DAY
io_cost=#mrds*mreadtim/sreadtime=round(2656/8)*26/12=719
计算cpu_cost
explain plan for select * from T_KINGDEE_CONSUME_DAY;
select * from table(dbms_xplan.display());
select cpu_cost from plan_table;
CPU_COST
------
135954115
cpu_cost=135954115/(3074*12)/1000=3.68
整体cost=io_cost+cpu_cost=719+3.7=722.7
查看trace文件部分:
SINGLE TABLE ACCESS PATH
Single Table Cardinality Estimation for T_KINGDEE_CONSUME_DAY[T_KINGDEE_CONSUME_DAY]
Table: T_KINGDEE_CONSUME_DAY Alias: T_KINGDEE_CONSUME_DAY
Card: Original: 377547.000000 Rounded: 377547 Computed: 377547.00 Non Adjusted: 377547.00
Access Path: TableScan
Cost: 724.69 Resp: 724.69 Degree: 0
Cost_io: 721.00 Cost_cpu: 135954115
Resp_io: 721.00 Resp_cpu: 135954115
Best:: AccessPath: TableScan
Cost: 724.69 Degree: 1 Resp: 724.69 Card: 377547.00 Bytes: 0
调整mbrc
SQL> alter system set db_file_multiblock_read_count=64 scope=both;
查看trace:
SYSTEM STATISTICS INFORMATION
Using NOWORKLOAD Stats
CPUSPEEDNW: 3074 millions instructions/sec (default is 100)
IOTFRSPEED: 4096 bytes per millisecond (default is 4096)
IOSEEKTIM: 10 milliseconds (default is 10)
MBRC: NO VALUE blocks (default is 64)
再次计算成本:
sreadtim=ioseektim+db_block_size/IOTFRSPEED=10+8192/4096=12
mreadtim=ioseektim+dbfilemultiblockreadcount * dbblocksize/IOTFRSPEED=10+64 * 8/4=138
io_cost=#mrds*mreadtim/sreadtime=round(2656/64,2)*138/12=477.25
cpu cost未变;
cost=io_cost+cpu_cost=3.68+477.25=480.93
没调整db_file_multiblock_read_count之前为721,调整后下降很多;
查看10053结果:
Access path analysis for T_KINGDEE_CONSUME_DAY
SINGLE TABLE ACCESS PATH
Single Table Cardinality Estimation for T_KINGDEE_CONSUME_DAY[T_KINGDEE_CONSUME_DAY]
Table: T_KINGDEE_CONSUME_DAY Alias: T_KINGDEE_CONSUME_DAY
Card: Original: 377547.000000 Rounded: 377547 Computed: 377547.00 Non Adjusted: 377547.00
Access Path: TableScan
Cost: 482.69 Resp: 482.69 Degree: 0
Cost_io: 479.00 Cost_cpu: 135954115
Resp_io: 479.00 Resp_cpu: 135954115
Best:: AccessPath: TableScan
Cost: 482.69 Degree: 1 Resp: 482.69 Card: 377547.00 Bytes: 0s
查看explain结果:
PLAN_TABLE_OUTPUT
--------------------------------------------------------------
Plan hash value: 873558201
----------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 377K| 14M| 483 (1)| 00:00:06 |
| 1 | TABLE ACCESS FULL| T_KINGDEE_CONSUME_DAY | 377K| 14M| 483 (1)| 00:00:06 |
发现差一点,483-482,但这里计算的比trace里的差1位,这个差距由参数_table_scan_cost_plus_one控制;
检查参数:
SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ FROM x$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%';
禁用alter session set "_table_scan_cost_plus_one"=false;
再次查看执行计划:
Plan hash value: 873558201
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 377K| 14M| 482 (1)| 00:00:06 |
| 1 | TABLE ACCESS FULL| T_KINGDEE_CONSUME_DAY | 377K| 14M| 482 (1)| 00:00:06 |
-------------------------------------------------------------------------------------------
再次调整_table_scan_cost_plus_one为false,后由483降为482;
结论:
db_file_multiblock_read_count这参数会影响你cost(%cpu)的整个结果;