[20250815]关于CPU成本计算(补充)2.txt
[20250815]关于CPU成本计算(补充)2.txt
--//以前测试过,当时一边做一边猜测,反推X,Y,Z的值,有点乱,做一些必要的整理,补充索引的一些测试。
--//看Jonathan Lewis的<基于成本的Oracle优化法则>,里面提到P51:
Finding out exactly where the original count of 72,914,400 operations came from is much
harder. If you care to run through a set of extremely tedious experiments, you could probably
track it down—approximately—to details like these:
. Cost of acquiring a block = X
. Cost of locating a row in a block = Y
. Cost of acquiring the Nth (in our case the 2nd) column in a row = (N - 1) * Z
. Cost of comparing a numeric column with a numeric constant = A
--//每块的CPU COST X=7121.44。
--//每行的CPU COST Y=150
--//每列的CPU COST Z=20,注意计算Highest_column_id
--//谓词部分使用常量比较成本 A=50
--//谓词部分使用绑定变量比较成本 A=150。
--//补充谓词部分字段参与运算成本的情况,每增加1个字段增加50,或者增加一个运算增加50.
--//以前测试在谓词使用函数存在问题,各种函数的成本并不是固定,另外写一篇blog说明。
--//扫描唯一索引块成本 1050。
--//里面的X,Y,Z值很容易确定,后面的测试有一些混乱,重新做1次,以前的测试参考:[20190821]关于CPU成本计算.txt
1.环境:
SCOTT@book01p> @ver2
==============================
PORT_STRING : x86_64/Linux 2.4.xx
VERSION : 21.0.0.0.0
BANNER : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
BANNER_FULL : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0
BANNER_LEGACY : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
CON_ID : 0
PL/SQL procedure successfully completed.
2.测试1:
SCOTT@book01p> create table t as select rownum a1 , rownum a2 ,rownum a3 from dual connect by level<=100 ;
Table created.
--//分析表略。
SCOTT@book01p> select blocks,num_rows from user_tables where table_name='T';
BLOCKS NUM_ROWS
---------- ----------
4 100
column STATEMENT_ID format a10
column OPTIONS format a10
column time format 9999
explain plan set statement_id='a1' for select 1 from t where a1=1;
explain plan set statement_id='a2' for select 1 from t where a2=1;
explain plan set statement_id='a3' for select 1 from t where a3=1;
explain plan set statement_id='a1x' for select 1 from t where a1=:N1;
explain plan set statement_id='a2x' for select 1 from t where a2=:N1;
explain plan set statement_id='a3x' for select 1 from t where a3=:N1;
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where options='FULL';
STATEMENT_ OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------- ------------------------------ ---------- ---------- ---------- ---------- -----
a1 TABLE ACCESS FULL 3 48486 3 1
a2 TABLE ACCESS FULL 3 50486 3 1
a3 TABLE ACCESS FULL 3 52486 3 1
a1x TABLE ACCESS FULL 3 58486 3 1
a2x TABLE ACCESS FULL 3 60486 3 1
a3x TABLE ACCESS FULL 3 62486 3 1
6 rows selected.
--//select部分cost,没有查询字段。
7121.44 * blocks + 150*rows + 20*rows* ( Highest_column_id - Lowest_column_id)
= 7121.44 * 4 + 150*100 + 20*150*(1-1) = 43485.76 = 43486
--//可以发现where中cost对比如下:
--//使用非绑定变量的情况:
a1=1 48486-43486 = 5000
a2=1 50486-43486 = 7000
a3=1 52486-43486 = 9000
--//使用绑定变量的情况:
a1=:N1 58486-43486 = 15000
a2=:N1 60486-43486 = 17000
a3=:N1 62486-43486 = 19000
--//使用非绑定变量的情况:
--//对应a1=100条件,表T共用100条记录,对比100次,这样每次比较5000/100 = 50.
--//以此类推a2=100,每次7000/100 = 70.a3=100,每次9000/100 = 90.
--//结合前面的Z=20(20 CPU Cycles for Column Skip).where的cost实际上的计算公式如下:
rows*50+rows*((Highest_column_id-1)*20).
--//实际上可以理解每次比较的cpu cost是50. 也就是可以 A=50.
--//使用绑定变量的情况:
--//与前面类似,很容易推导使用绑定变量每次比较的CPU COST = 150.
--//注真实的情况也许很复杂,也许谓词存在and 或者 or ,这样我估计oracle优先选择在选择性很好的字段做比较。
--//参考:[20190821]关于CPU成本计算.txt,里面有一些更复杂的测试。
3.测试2:
--//测试谓词使用函数的情况,推断使用函数的cpu cost。
--//测试前退出在登录,因为查询plan_table是临时表。
column STATEMENT_ID format a10
column OPTIONS format a10
column time format 9999
explain plan set statement_id='a1' for select 1 from t where to_char(a1)='1';
explain plan set statement_id='a2' for select 1 from t where to_char(a2)='1';
explain plan set statement_id='a3' for select 1 from t where to_char(a3)='1';
explain plan set statement_id='a1x' for select 1 from t where to_char(a1)=:N1;
explain plan set statement_id='a2x' for select 1 from t where to_char(a2)=:N1;
explain plan set statement_id='a3x' for select 1 from t where to_char(a3)=:N1;
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where options='FULL';
STATEMENT_ OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------- ------------------------------ ---------- ---------- ---------- ---------- -----
a1 TABLE ACCESS FULL 3 58486 3 1
a2 TABLE ACCESS FULL 3 60486 3 1
a3 TABLE ACCESS FULL 3 62486 3 1
a1x TABLE ACCESS FULL 3 58486 3 1
a2x TABLE ACCESS FULL 3 60486 3 1
a3x TABLE ACCESS FULL 3 62486 3 1
6 rows selected.
--//select部分cost,没有查询字段。
7121.44 * blocks + 150*rows + 20*rows* ( Highest_column_id - Lowest_column_id)
= 7121.44 * 4 + 150*100 + 20*150*(1-1) = 43485.76 = 43486
--//可以发现where中cost对比如下:
--//使用非绑定变量的情况:
to_char(a1)='1' 58486-43486 = 15000
to_char(a2)='1' 60486-43486 = 17000
to_char(a3)='1' 62486-43486 = 19000
--//使用绑定变量的情况:
to_char(a1)=:N1; 58486-43486 = 15000
to_char(a2)=:N1; 60486-43486 = 17000
to_char(a3)=:N1; 62486-43486 = 19000
--//可以发现where中cost对比如下:
to_char(a1)='1' 58486-43486 = 15000
to_char(a2)='1' 60486-43486 = 17000
to_char(a3)='1' 62486-43486 = 19000
--//对应a1=100条件,表T共用100条记录,对比100次,这样每次 15000/100 = 150.
--//以此类推a2=100,每次17000/100 = 170.a3=100,每次19000/100 = 190.
--//根据前面的测试,排除字段的成本(20),比较每次50,可以推断函数部分占100,感觉这部分也太少了!!
--//字段= 常量的比较每次50,而引入函数仅仅增加100。我个人感觉oracle设置太小了,应该设置500.
--//注:我一直以为所有的函数的成本都是一样的,实际的情况各个函数不同,另外写一篇blog说明,我这里的测试使用to_char实际上
--//是使用函数里面最小的情况。
--//换一个测试方法:
SCOTT@book01p> explain plan set statement_id='xxx' for select to_char(a1) from t where rownum=1;
Explained.
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where statement_id='xxx';
STATEMENT_ OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------- ------------------------------ ---------- ---------- ---------- ---------- -----
xxx SELECT STATEMENT 2 7271 2 1
xxx COUNT STOPKEY
xxx TABLE ACCESS FULL 2 7271 2 1
--//select部分:
7121.44 * blocks + 150*rows + 20*rows* ( Highest_column_id - 1)
= 7121.44 * 1 + 150*1 = 7271.44
--//在select出现的函数不计算cost。
4.测试3:
--//测试谓词部分字段运算成本,这部分以前没有测试过。
column STATEMENT_ID format a16
column OPTIONS format a10
column time format 9999
explain plan set statement_id='A1+1' for select 1 from t where a1+1=100;
explain plan set statement_id='A1+A1' for select 1 from t where a1+a1=100;
explain plan set statement_id='A1+A2' for select 1 from t where a1+a2=100;
explain plan set statement_id='A1+A2*2' for select 1 from t where a1+a2*2=100;
explain plan set statement_id='A1+A2+A3' for select 1 from t where A1+A2+A3=100;
explain plan set statement_id='power(A1)+A2' for select 1 from t where power(A1,2)+A2=100;
explain plan set statement_id='XA1+1' for select 1 from t where a1+1=:N1;
explain plan set statement_id='XA1+A1' for select 1 from t where a1+a1=:N1;
explain plan set statement_id='XA1+A2' for select 1 from t where a1+a2=:N1;
explain plan set statement_id='XA1+A2*2' for select 1 from t where a1+a2*2=:N1;
explain plan set statement_id='XA1+A2+A3' for select 1 from t where A1+A2+A3=:N1;
explain plan set statement_id='Xpower(A1)+A2' for select 1 from t where power(A1,2)+A2=:N1;
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where options='FULL';
STATEMENT_ID OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------------- ------------------------------ ---------- ---------- ---------- ---------- -----
A1+1 TABLE ACCESS FULL 3 53486 3 1
A1+A1 TABLE ACCESS FULL 3 53486 3 1
A1+A2 TABLE ACCESS FULL 3 55486 3 1
A1+A2*2 TABLE ACCESS FULL 3 60486 3 1
A1+A2+A3 TABLE ACCESS FULL 3 62486 3 1
power(A1)+A2 TABLE ACCESS FULL 3 80486 3 1
XA1+1 TABLE ACCESS FULL 3 63486 3 1
XA1+A1 TABLE ACCESS FULL 3 63486 3 1
XA1+A2 TABLE ACCESS FULL 3 65486 3 1
XA1+A2*2 TABLE ACCESS FULL 3 70486 3 1
XA1+A2+A3 TABLE ACCESS FULL 3 72486 3 1
Xpower(A1)+A2 TABLE ACCESS FULL 3 90486 3 1
12 rows selected.
--//select部分cost,没有查询字段。
7121.44 * blocks + 150*rows + 20*rows* ( Highest_column_id - Lowest_column_id)
= 7121.44 * 4 + 150*100 + 20*150*(1-1) = 43485.76 = 43486
--//可以发现where中cost对比如下:
--//使用非绑定变量的情况:
A1+1 53486 - 43486 = 10000
A1+A1 53486 - 43486 = 10000
A1+A2 55486 - 43486 = 12000
A1+A2*2 60486 - 43486 = 17000
A1+A2+A3 62486 - 43486 = 19000
power(A1)+A2 80486 - 43486 = 37000
--//带运算比较的起点是100,有字段参与运算,oracle并不像函数那样A=150. 而是根据运算的不同发生一些变化。
--//注意排序字段成本每个20.
A1+1 100
A1+A1 100
A1+A2 100
A1+A2*2 150
A1+A2+A3 150
power(A1)+A2 350
--//使用绑定变量的情况:
XA1+1 63486 - 43486 = 20000
XA1+A1 63486 - 43486 = 20000
XA1+A2 65486 - 43486 = 22000
XA1+A2*2 70486 - 43486 = 27000
XA1+A2+A3 72486 - 43486 = 29000
Xpower(A1)+A2 90486 - 43486 = 47000
--//对比前面非绑定变量的情况,每个总的增加10000,也就是每次比较比非绑定变量增加100.
--//注意排序字段成本每个20.
XA1+1 200
XA1+A1 200
XA1+A2 200
XA1+A2*2 250
XA1+A2+A3 250
Xpower(A1)+A2 450
--//还是简单看出一些规律,比如增加1个简单运算增50,是否各个函数有关cost,oracle内部存在定义,power(A1,2)定义300.
--//也许前面测试使用to_char函数定义很低。
--//采用绑定变量增100.
--//补充测试:
column STATEMENT_ID format a10
column OPTIONS format a10
column time format 9999
explain plan set statement_id='p1' for select 1 from t where power(A1,2)=100;
explain plan set statement_id='p2' for select 1 from t where power(A1,2)=:N1;
explain plan set statement_id='s1' for select 1 from t where sqrt(A1)=100;
explain plan set statement_id='s2' for select 1 from t where sqrt(A1)=:N1;
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where options='FULL';
STATEMENT_ID OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------------- ------------------------------ ---------- ---------- ---------- ---------- -----
p1 TABLE ACCESS FULL 3 73486 3 1
p2 TABLE ACCESS FULL 3 83486 3 1
s1 TABLE ACCESS FULL 3 68486 3 1
s2 TABLE ACCESS FULL 3 78486 3 1
power(A1,2)=100; 73486-43486 = 30000
power(A1,2)=:N1; 83486-43486 = 40000
sqrt(A1)=100; 68486-43486 = 25000
sqrt(A1)=:N1; 78486-43486 = 35000
--//看来oracle每个函数的定义都不相同。
explain plan set statement_id='q1' for select power(a1,2) from t where rownum=1;
explain plan set statement_id='q2' for select sqrt(a1) from t where rownum=1;
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where options='FULL' and STATEMENT_ID like 'q%';
STATEMENT_ID OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------------- ------------------------------ ---------- ---------- ---------- ---------- -----
q1 TABLE ACCESS FULL 2 7271 2 1
q2 TABLE ACCESS FULL 2 7271 2 1
--//select部分:
7121.44 * blocks + 150*rows + 20*rows* ( Highest_column_id - 1)
= 7121.44 * 1 + 150*1 = 7271.44
--//在select出现的函数不计算cost。
5.测试4:
--//建立索引看看。
SCOTT@book01p> create unique index i_t_a3 on t(a3);
Index created.
SCOTT@book01p> create index i_t_a2 on t(a2);
Index created.
column STATEMENT_ID format a10
column OPTIONS format a12
column time format 9999
explain plan set statement_id='b2' for select 1 from t where a2 = 50;
explain plan set statement_id='b3' for select 1 from t where a3 = 50;
explain plan set statement_id='b2x' for select 1 from t where a2 = :N1;
explain plan set statement_id='b3x' for select 1 from t where a3 = :N1;
SCOTT@book01p> column OPTIONS format a12
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where OPERATION='INDEX';
STATEMENT_ OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------- ------------------------------ ------------ ---------- ---------- ---------- -----
b2 INDEX RANGE SCAN 1 7321 1 1
b3 INDEX UNIQUE SCAN 0 1050 0 1
b2x INDEX RANGE SCAN 1 7321 1 1
b3x INDEX UNIQUE SCAN 0 1050 0 1
--//RANGE SCAN , UNIQUE SCAN 不同,前者7321. 后者1050.
explain plan set statement_id='b2' for select 1 from t where a2 = 50;
--//select部分:
7121.44 * blocks + 150*rows + 20*rows* ( Highest_column_id - 1)
7121.44 * 0 + 150*0 = 0
--//索引部分,实际上与数据块类似,可以想象索引就是仅仅包含索引字段的表,如果不是唯一索引与数据块类似。
7121.44 * blocks + 150*rows + 50*compare_counts
7121.44 * 1 + 150*1 = 7271.44
--//比较部分成本1次:50
7271.44+50 = 7321.44
explain plan set statement_id='b3' for select 1 from t where a3 = 50;
--//select部分:
7121.44 * blocks + 150*rows + 20*rows* ( Highest_column_id - 1)
7121.44 * 0 + 150*0 = 0
--//比较部分成本1次:50
--//这样扫描索引块的成本就是1000.
--//继续探究索引的如何计算:
column STATEMENT_ID format a10
column OPTIONS format a12
column time format 9999
explain plan set statement_id='c1' for select 1 from t where a3 between 1 and 1;
explain plan set statement_id='c2' for select 1 from t where a3 between 1 and 2;
explain plan set statement_id='c3' for select 1 from t where a3 between 1 and 3;
explain plan set statement_id='c4' for select 1 from t where a3 between 1 and 4;
explain plan set statement_id='c5' for select 1 from t where a3 between 1 and 5;
explain plan set statement_id='c6' for select 1 from t where a3 between 1 and 6;
explain plan set statement_id='c7' for select 1 from t where a3 between 1 and 7;
explain plan set statement_id='c8' for select 1 from t where a3 between 1 and 8;
explain plan set statement_id='c9' for select 1 from t where a3 between 1 and 9;
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where STATEMENT_ID like 'c%' and OPERATION='INDEX';
STATEMENT_ OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------- ------------------------------ ------------ ---------- ---------- ---------- -----
c1 INDEX UNIQUE SCAN 0 1050 0 1
c2 INDEX RANGE SCAN 1 7721 1 1
c3 INDEX RANGE SCAN 1 7921 1 1
c4 INDEX RANGE SCAN 1 8121 1 1
c5 INDEX RANGE SCAN 1 8321 1 1
c6 INDEX RANGE SCAN 1 8521 1 1
c7 INDEX RANGE SCAN 1 8721 1 1
c8 INDEX RANGE SCAN 1 8921 1 1
c9 INDEX RANGE SCAN 1 9121 1 1
9 rows selected.
--//a3 between 1 and 1智能判断使用UNIQUE SCAN,而RANGE SCAN,每次增加1,查询的cost增加200.
--//explain plan set statement_id='c2' for select 1 from t where a3 between 1 and 2;
--//7721-7121 = 600 ,增加600.
--//你可以想象索引就是仅仅包含索引字段的表,a3 between 1 and 2相当于比较3次。
--//按照情况,扫描索引数据块1,3行,比较3次来计算。
7121.44 * blocks + 150*rows + 50*compare_counts
7121.44 * 1 + 150*3 + 20*rows* ( 1 - 1) + 50*3 = 7721.44
--//仅仅对于唯一索引扫描不同其CPU COST成本 1000+50。
6.补充一些例子说明问题:
SCOTT@book01p> column OPTIONS format a30
SCOTT@book01p> explain plan set statement_id='e3' for select a3 from t where a2 = 50;
Explained.
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where STATEMENT_ID like 'e3';
STATEMENT_ OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------- ------------------------------ ------------------------------ ---------- ---------- ---------- -----
e3 SELECT STATEMENT 2 14633 2 1
e3 TABLE ACCESS BY INDEX ROWID BATCHED 2 14633 2 1
e3 INDEX RANGE SCAN 1 7321 1 1
--//索引部分:
7121.44 * blocks + 150*rows + 50*compare_counts
7121.44 * 1 + 150*1 + 50*1 = 7321.44
--//select部分:
7121.44 * blocks + 150*rows + 20*rows* ( Highest_column_id - Lowest_column_id)
==7121.44 * 1 + 150*1 + 20*1* (3-1)
=7311.44
--//7321.44+7311.44 = 14632.88
--//取整正好是14633
--//删除索引。
SCOTT@book01p> drop index i_t_a3;
Index dropped.
SCOTT@book01p> drop index i_t_a2;
Index dropped.
SCOTT@book01p> explain plan set statement_id='e4' for select a2 from t where a3 = 50;
Explained.
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where STATEMENT_ID like 'e4';
STATEMENT_ OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------- ------------------------------ ------------------------------ ---------- ---------- ---------- -----
e4 SELECT STATEMENT 3 52486 3 1
e4 TABLE ACCESS FULL 3 52486 3 1
--//谓词比较部分:
--//比较100次,这样比较cost 50*100 = 5000
--//select部分:
7121.44 * blocks + 150*rows + 20*rows* ( Highest_column_id - Lowest_column_id)
=7121.44 * 4 + 150*100 + 20*100* (3-1)
=47485.76
--//47485.76+5000 = 52485.76
--//注意Highest_column_id =3,因为where a3 = 50。
--//重复以前的1个例子:
SCOTT@book01p> explain plan set statement_id='bb' for select a3 from t where a2=100 ;
Explained.
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where STATEMENT_ID='bb';
STATEMENT_ OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------- ---------------- ------- ---- -------- ------- ----
bb SELECT STATEMENT 3 50506 3 1
bb TABLE ACCESS FULL 3 50506 3 1
--//我先说说我的理解然后计算:
--//如果查询时第1条记录是a2=1,这样根本不用取a3字段直接跳过这条记录,这样select部分仅仅取a2后然后比较
--//如果a2=100符合查询条件再取字段a3.有了这样理解cpu cost计算就简单了.
--//select部分,开始仅仅需要取到a2字段(即使select部分包含a3):
7121.44 * blocks + 150*rows + 20*rows* (Highest_column_id - Lowest_column_id)
7121.44 * 4 + 150*100 + 20*rows* ( 2 - 1) = 43485.76 + 2000 = 45486
--//where部分:
比较100次 100*50=5000
仅仅1条符合a2=100.取a3字段成本 :
20*rows* (Highest_column_id - Lowest_column_id)
20*1*(3-2) = 20
--//cpu cost
45486 + 5000+ 20 = 50506
--//完全符合.
--//补充说明:字段成本分2次计算
--//第一次是 20*rows* ( Highest_column - Lowest_column) ,这里的Highest_column=2,Lowest_column=1.rows=100.
--//第二次是 20*rows* ( Highest_column - Lowest_column) ,这里的Highest_column=3,Lowest_column=2.rows=1.
--//总之字段成本要看select以及查询条件结合起来判断,出现的情况可能比较复杂.
6.再补充索引的情况:
--//删除前面建立的索引。
SCOTT@book01p> create index i_t_a3_a2 on t(a3,a2);
Index created.
SCOTT@book01p> explain plan set statement_id='f1' for select a1 from t where a3 = 50;
Explained.
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where STATEMENT_ID like 'f1%';
STATEMENT_ID OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------------- ------------------------------ ----------------------- ---------- ---------- ---------- -----
f1 SELECT STATEMENT 2 14633 2 1
f1 TABLE ACCESS BY INDEX ROWID BATCHED 2 14633 2 1
f1 INDEX RANGE SCAN 1 7321 1 1
--//分开2部分计算:
--//索引部分:
7121.44 * blocks + 150*rows + 20*rows* (Highest_column_id - Lowest_column_id)
7121.44+150+0 = 7271.44
--//比较1次 50
7271.44+50 = 7321.44
--//注意在索引a3是第1个字段。
--//select部分:
7121.44 * blocks + 150*rows + 20*rows* (Highest_column_id - Lowest_column_id)
7121.44+150+0 = 7271.44
7271.44+7321.44 = 14592.88
--//可以发现我的计算对不上,相差14633-14593 = 40。似乎取到A3字段。
7.总结:
--//首先以上大部分内容完全是先有cpu cost,再反推数值,也许内部的计算更复杂。
--//大概还是存在一些规律:
--//每块的CPU COST X=7121.44。
--//每行的CPU COST Y=150
--//每列的CPU COST Z=20,注意计算Highest_column_id
--//谓词部分使用常量比较成本 A=50 ,引入函数比较成本每个函数的成本不同!!
--//谓词部分使用绑定变量比较成本再增加 100。
--//补充谓词部分字段运算成本,每增加1个字段增加50,增加运算50.
--//扫描唯一索引块成本 1050。
--//在select出现的函数不计算cost。
--//CPU COST计算分成几个部分:
--//扫描块数量的成本
--//扫描行数量的成本
--//扫描字段的成本,取决于字段在段的位置。
--//建议反复看看explain plan set statement_id='bb' for select a3 from t where a2=100 ;的例子
--//可以理解分2部分。
--//谓词比较成本,50起步,增加1个运算增50,增加1个字段增50。注:仅仅是我上面观察到的结果。
--//谓词部分使用绑定变量比较成本再增加 100。
--//索引部分的情况类似,你可以把索引想象为包含索引字段的表,与数据块部分分开计算。
--//特殊的情况是唯一索引扫描,块的成本是1050.
--//以前测试过,当时一边做一边猜测,反推X,Y,Z的值,有点乱,做一些必要的整理,补充索引的一些测试。
--//看Jonathan Lewis的<基于成本的Oracle优化法则>,里面提到P51:
Finding out exactly where the original count of 72,914,400 operations came from is much
harder. If you care to run through a set of extremely tedious experiments, you could probably
track it down—approximately—to details like these:
. Cost of acquiring a block = X
. Cost of locating a row in a block = Y
. Cost of acquiring the Nth (in our case the 2nd) column in a row = (N - 1) * Z
. Cost of comparing a numeric column with a numeric constant = A
--//每块的CPU COST X=7121.44。
--//每行的CPU COST Y=150
--//每列的CPU COST Z=20,注意计算Highest_column_id
--//谓词部分使用常量比较成本 A=50
--//谓词部分使用绑定变量比较成本 A=150。
--//补充谓词部分字段参与运算成本的情况,每增加1个字段增加50,或者增加一个运算增加50.
--//以前测试在谓词使用函数存在问题,各种函数的成本并不是固定,另外写一篇blog说明。
--//扫描唯一索引块成本 1050。
--//里面的X,Y,Z值很容易确定,后面的测试有一些混乱,重新做1次,以前的测试参考:[20190821]关于CPU成本计算.txt
1.环境:
SCOTT@book01p> @ver2
==============================
PORT_STRING : x86_64/Linux 2.4.xx
VERSION : 21.0.0.0.0
BANNER : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
BANNER_FULL : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0
BANNER_LEGACY : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
CON_ID : 0
PL/SQL procedure successfully completed.
2.测试1:
SCOTT@book01p> create table t as select rownum a1 , rownum a2 ,rownum a3 from dual connect by level<=100 ;
Table created.
--//分析表略。
SCOTT@book01p> select blocks,num_rows from user_tables where table_name='T';
BLOCKS NUM_ROWS
---------- ----------
4 100
column STATEMENT_ID format a10
column OPTIONS format a10
column time format 9999
explain plan set statement_id='a1' for select 1 from t where a1=1;
explain plan set statement_id='a2' for select 1 from t where a2=1;
explain plan set statement_id='a3' for select 1 from t where a3=1;
explain plan set statement_id='a1x' for select 1 from t where a1=:N1;
explain plan set statement_id='a2x' for select 1 from t where a2=:N1;
explain plan set statement_id='a3x' for select 1 from t where a3=:N1;
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where options='FULL';
STATEMENT_ OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------- ------------------------------ ---------- ---------- ---------- ---------- -----
a1 TABLE ACCESS FULL 3 48486 3 1
a2 TABLE ACCESS FULL 3 50486 3 1
a3 TABLE ACCESS FULL 3 52486 3 1
a1x TABLE ACCESS FULL 3 58486 3 1
a2x TABLE ACCESS FULL 3 60486 3 1
a3x TABLE ACCESS FULL 3 62486 3 1
6 rows selected.
--//select部分cost,没有查询字段。
7121.44 * blocks + 150*rows + 20*rows* ( Highest_column_id - Lowest_column_id)
= 7121.44 * 4 + 150*100 + 20*150*(1-1) = 43485.76 = 43486
--//可以发现where中cost对比如下:
--//使用非绑定变量的情况:
a1=1 48486-43486 = 5000
a2=1 50486-43486 = 7000
a3=1 52486-43486 = 9000
--//使用绑定变量的情况:
a1=:N1 58486-43486 = 15000
a2=:N1 60486-43486 = 17000
a3=:N1 62486-43486 = 19000
--//使用非绑定变量的情况:
--//对应a1=100条件,表T共用100条记录,对比100次,这样每次比较5000/100 = 50.
--//以此类推a2=100,每次7000/100 = 70.a3=100,每次9000/100 = 90.
--//结合前面的Z=20(20 CPU Cycles for Column Skip).where的cost实际上的计算公式如下:
rows*50+rows*((Highest_column_id-1)*20).
--//实际上可以理解每次比较的cpu cost是50. 也就是可以 A=50.
--//使用绑定变量的情况:
--//与前面类似,很容易推导使用绑定变量每次比较的CPU COST = 150.
--//注真实的情况也许很复杂,也许谓词存在and 或者 or ,这样我估计oracle优先选择在选择性很好的字段做比较。
--//参考:[20190821]关于CPU成本计算.txt,里面有一些更复杂的测试。
3.测试2:
--//测试谓词使用函数的情况,推断使用函数的cpu cost。
--//测试前退出在登录,因为查询plan_table是临时表。
column STATEMENT_ID format a10
column OPTIONS format a10
column time format 9999
explain plan set statement_id='a1' for select 1 from t where to_char(a1)='1';
explain plan set statement_id='a2' for select 1 from t where to_char(a2)='1';
explain plan set statement_id='a3' for select 1 from t where to_char(a3)='1';
explain plan set statement_id='a1x' for select 1 from t where to_char(a1)=:N1;
explain plan set statement_id='a2x' for select 1 from t where to_char(a2)=:N1;
explain plan set statement_id='a3x' for select 1 from t where to_char(a3)=:N1;
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where options='FULL';
STATEMENT_ OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------- ------------------------------ ---------- ---------- ---------- ---------- -----
a1 TABLE ACCESS FULL 3 58486 3 1
a2 TABLE ACCESS FULL 3 60486 3 1
a3 TABLE ACCESS FULL 3 62486 3 1
a1x TABLE ACCESS FULL 3 58486 3 1
a2x TABLE ACCESS FULL 3 60486 3 1
a3x TABLE ACCESS FULL 3 62486 3 1
6 rows selected.
--//select部分cost,没有查询字段。
7121.44 * blocks + 150*rows + 20*rows* ( Highest_column_id - Lowest_column_id)
= 7121.44 * 4 + 150*100 + 20*150*(1-1) = 43485.76 = 43486
--//可以发现where中cost对比如下:
--//使用非绑定变量的情况:
to_char(a1)='1' 58486-43486 = 15000
to_char(a2)='1' 60486-43486 = 17000
to_char(a3)='1' 62486-43486 = 19000
--//使用绑定变量的情况:
to_char(a1)=:N1; 58486-43486 = 15000
to_char(a2)=:N1; 60486-43486 = 17000
to_char(a3)=:N1; 62486-43486 = 19000
--//可以发现where中cost对比如下:
to_char(a1)='1' 58486-43486 = 15000
to_char(a2)='1' 60486-43486 = 17000
to_char(a3)='1' 62486-43486 = 19000
--//对应a1=100条件,表T共用100条记录,对比100次,这样每次 15000/100 = 150.
--//以此类推a2=100,每次17000/100 = 170.a3=100,每次19000/100 = 190.
--//根据前面的测试,排除字段的成本(20),比较每次50,可以推断函数部分占100,感觉这部分也太少了!!
--//字段= 常量的比较每次50,而引入函数仅仅增加100。我个人感觉oracle设置太小了,应该设置500.
--//注:我一直以为所有的函数的成本都是一样的,实际的情况各个函数不同,另外写一篇blog说明,我这里的测试使用to_char实际上
--//是使用函数里面最小的情况。
--//换一个测试方法:
SCOTT@book01p> explain plan set statement_id='xxx' for select to_char(a1) from t where rownum=1;
Explained.
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where statement_id='xxx';
STATEMENT_ OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------- ------------------------------ ---------- ---------- ---------- ---------- -----
xxx SELECT STATEMENT 2 7271 2 1
xxx COUNT STOPKEY
xxx TABLE ACCESS FULL 2 7271 2 1
--//select部分:
7121.44 * blocks + 150*rows + 20*rows* ( Highest_column_id - 1)
= 7121.44 * 1 + 150*1 = 7271.44
--//在select出现的函数不计算cost。
4.测试3:
--//测试谓词部分字段运算成本,这部分以前没有测试过。
column STATEMENT_ID format a16
column OPTIONS format a10
column time format 9999
explain plan set statement_id='A1+1' for select 1 from t where a1+1=100;
explain plan set statement_id='A1+A1' for select 1 from t where a1+a1=100;
explain plan set statement_id='A1+A2' for select 1 from t where a1+a2=100;
explain plan set statement_id='A1+A2*2' for select 1 from t where a1+a2*2=100;
explain plan set statement_id='A1+A2+A3' for select 1 from t where A1+A2+A3=100;
explain plan set statement_id='power(A1)+A2' for select 1 from t where power(A1,2)+A2=100;
explain plan set statement_id='XA1+1' for select 1 from t where a1+1=:N1;
explain plan set statement_id='XA1+A1' for select 1 from t where a1+a1=:N1;
explain plan set statement_id='XA1+A2' for select 1 from t where a1+a2=:N1;
explain plan set statement_id='XA1+A2*2' for select 1 from t where a1+a2*2=:N1;
explain plan set statement_id='XA1+A2+A3' for select 1 from t where A1+A2+A3=:N1;
explain plan set statement_id='Xpower(A1)+A2' for select 1 from t where power(A1,2)+A2=:N1;
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where options='FULL';
STATEMENT_ID OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------------- ------------------------------ ---------- ---------- ---------- ---------- -----
A1+1 TABLE ACCESS FULL 3 53486 3 1
A1+A1 TABLE ACCESS FULL 3 53486 3 1
A1+A2 TABLE ACCESS FULL 3 55486 3 1
A1+A2*2 TABLE ACCESS FULL 3 60486 3 1
A1+A2+A3 TABLE ACCESS FULL 3 62486 3 1
power(A1)+A2 TABLE ACCESS FULL 3 80486 3 1
XA1+1 TABLE ACCESS FULL 3 63486 3 1
XA1+A1 TABLE ACCESS FULL 3 63486 3 1
XA1+A2 TABLE ACCESS FULL 3 65486 3 1
XA1+A2*2 TABLE ACCESS FULL 3 70486 3 1
XA1+A2+A3 TABLE ACCESS FULL 3 72486 3 1
Xpower(A1)+A2 TABLE ACCESS FULL 3 90486 3 1
12 rows selected.
--//select部分cost,没有查询字段。
7121.44 * blocks + 150*rows + 20*rows* ( Highest_column_id - Lowest_column_id)
= 7121.44 * 4 + 150*100 + 20*150*(1-1) = 43485.76 = 43486
--//可以发现where中cost对比如下:
--//使用非绑定变量的情况:
A1+1 53486 - 43486 = 10000
A1+A1 53486 - 43486 = 10000
A1+A2 55486 - 43486 = 12000
A1+A2*2 60486 - 43486 = 17000
A1+A2+A3 62486 - 43486 = 19000
power(A1)+A2 80486 - 43486 = 37000
--//带运算比较的起点是100,有字段参与运算,oracle并不像函数那样A=150. 而是根据运算的不同发生一些变化。
--//注意排序字段成本每个20.
A1+1 100
A1+A1 100
A1+A2 100
A1+A2*2 150
A1+A2+A3 150
power(A1)+A2 350
--//使用绑定变量的情况:
XA1+1 63486 - 43486 = 20000
XA1+A1 63486 - 43486 = 20000
XA1+A2 65486 - 43486 = 22000
XA1+A2*2 70486 - 43486 = 27000
XA1+A2+A3 72486 - 43486 = 29000
Xpower(A1)+A2 90486 - 43486 = 47000
--//对比前面非绑定变量的情况,每个总的增加10000,也就是每次比较比非绑定变量增加100.
--//注意排序字段成本每个20.
XA1+1 200
XA1+A1 200
XA1+A2 200
XA1+A2*2 250
XA1+A2+A3 250
Xpower(A1)+A2 450
--//还是简单看出一些规律,比如增加1个简单运算增50,是否各个函数有关cost,oracle内部存在定义,power(A1,2)定义300.
--//也许前面测试使用to_char函数定义很低。
--//采用绑定变量增100.
--//补充测试:
column STATEMENT_ID format a10
column OPTIONS format a10
column time format 9999
explain plan set statement_id='p1' for select 1 from t where power(A1,2)=100;
explain plan set statement_id='p2' for select 1 from t where power(A1,2)=:N1;
explain plan set statement_id='s1' for select 1 from t where sqrt(A1)=100;
explain plan set statement_id='s2' for select 1 from t where sqrt(A1)=:N1;
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where options='FULL';
STATEMENT_ID OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------------- ------------------------------ ---------- ---------- ---------- ---------- -----
p1 TABLE ACCESS FULL 3 73486 3 1
p2 TABLE ACCESS FULL 3 83486 3 1
s1 TABLE ACCESS FULL 3 68486 3 1
s2 TABLE ACCESS FULL 3 78486 3 1
power(A1,2)=100; 73486-43486 = 30000
power(A1,2)=:N1; 83486-43486 = 40000
sqrt(A1)=100; 68486-43486 = 25000
sqrt(A1)=:N1; 78486-43486 = 35000
--//看来oracle每个函数的定义都不相同。
explain plan set statement_id='q1' for select power(a1,2) from t where rownum=1;
explain plan set statement_id='q2' for select sqrt(a1) from t where rownum=1;
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where options='FULL' and STATEMENT_ID like 'q%';
STATEMENT_ID OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------------- ------------------------------ ---------- ---------- ---------- ---------- -----
q1 TABLE ACCESS FULL 2 7271 2 1
q2 TABLE ACCESS FULL 2 7271 2 1
--//select部分:
7121.44 * blocks + 150*rows + 20*rows* ( Highest_column_id - 1)
= 7121.44 * 1 + 150*1 = 7271.44
--//在select出现的函数不计算cost。
5.测试4:
--//建立索引看看。
SCOTT@book01p> create unique index i_t_a3 on t(a3);
Index created.
SCOTT@book01p> create index i_t_a2 on t(a2);
Index created.
column STATEMENT_ID format a10
column OPTIONS format a12
column time format 9999
explain plan set statement_id='b2' for select 1 from t where a2 = 50;
explain plan set statement_id='b3' for select 1 from t where a3 = 50;
explain plan set statement_id='b2x' for select 1 from t where a2 = :N1;
explain plan set statement_id='b3x' for select 1 from t where a3 = :N1;
SCOTT@book01p> column OPTIONS format a12
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where OPERATION='INDEX';
STATEMENT_ OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------- ------------------------------ ------------ ---------- ---------- ---------- -----
b2 INDEX RANGE SCAN 1 7321 1 1
b3 INDEX UNIQUE SCAN 0 1050 0 1
b2x INDEX RANGE SCAN 1 7321 1 1
b3x INDEX UNIQUE SCAN 0 1050 0 1
--//RANGE SCAN , UNIQUE SCAN 不同,前者7321. 后者1050.
explain plan set statement_id='b2' for select 1 from t where a2 = 50;
--//select部分:
7121.44 * blocks + 150*rows + 20*rows* ( Highest_column_id - 1)
7121.44 * 0 + 150*0 = 0
--//索引部分,实际上与数据块类似,可以想象索引就是仅仅包含索引字段的表,如果不是唯一索引与数据块类似。
7121.44 * blocks + 150*rows + 50*compare_counts
7121.44 * 1 + 150*1 = 7271.44
--//比较部分成本1次:50
7271.44+50 = 7321.44
explain plan set statement_id='b3' for select 1 from t where a3 = 50;
--//select部分:
7121.44 * blocks + 150*rows + 20*rows* ( Highest_column_id - 1)
7121.44 * 0 + 150*0 = 0
--//比较部分成本1次:50
--//这样扫描索引块的成本就是1000.
--//继续探究索引的如何计算:
column STATEMENT_ID format a10
column OPTIONS format a12
column time format 9999
explain plan set statement_id='c1' for select 1 from t where a3 between 1 and 1;
explain plan set statement_id='c2' for select 1 from t where a3 between 1 and 2;
explain plan set statement_id='c3' for select 1 from t where a3 between 1 and 3;
explain plan set statement_id='c4' for select 1 from t where a3 between 1 and 4;
explain plan set statement_id='c5' for select 1 from t where a3 between 1 and 5;
explain plan set statement_id='c6' for select 1 from t where a3 between 1 and 6;
explain plan set statement_id='c7' for select 1 from t where a3 between 1 and 7;
explain plan set statement_id='c8' for select 1 from t where a3 between 1 and 8;
explain plan set statement_id='c9' for select 1 from t where a3 between 1 and 9;
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where STATEMENT_ID like 'c%' and OPERATION='INDEX';
STATEMENT_ OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------- ------------------------------ ------------ ---------- ---------- ---------- -----
c1 INDEX UNIQUE SCAN 0 1050 0 1
c2 INDEX RANGE SCAN 1 7721 1 1
c3 INDEX RANGE SCAN 1 7921 1 1
c4 INDEX RANGE SCAN 1 8121 1 1
c5 INDEX RANGE SCAN 1 8321 1 1
c6 INDEX RANGE SCAN 1 8521 1 1
c7 INDEX RANGE SCAN 1 8721 1 1
c8 INDEX RANGE SCAN 1 8921 1 1
c9 INDEX RANGE SCAN 1 9121 1 1
9 rows selected.
--//a3 between 1 and 1智能判断使用UNIQUE SCAN,而RANGE SCAN,每次增加1,查询的cost增加200.
--//explain plan set statement_id='c2' for select 1 from t where a3 between 1 and 2;
--//7721-7121 = 600 ,增加600.
--//你可以想象索引就是仅仅包含索引字段的表,a3 between 1 and 2相当于比较3次。
--//按照情况,扫描索引数据块1,3行,比较3次来计算。
7121.44 * blocks + 150*rows + 50*compare_counts
7121.44 * 1 + 150*3 + 20*rows* ( 1 - 1) + 50*3 = 7721.44
--//仅仅对于唯一索引扫描不同其CPU COST成本 1000+50。
6.补充一些例子说明问题:
SCOTT@book01p> column OPTIONS format a30
SCOTT@book01p> explain plan set statement_id='e3' for select a3 from t where a2 = 50;
Explained.
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where STATEMENT_ID like 'e3';
STATEMENT_ OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------- ------------------------------ ------------------------------ ---------- ---------- ---------- -----
e3 SELECT STATEMENT 2 14633 2 1
e3 TABLE ACCESS BY INDEX ROWID BATCHED 2 14633 2 1
e3 INDEX RANGE SCAN 1 7321 1 1
--//索引部分:
7121.44 * blocks + 150*rows + 50*compare_counts
7121.44 * 1 + 150*1 + 50*1 = 7321.44
--//select部分:
7121.44 * blocks + 150*rows + 20*rows* ( Highest_column_id - Lowest_column_id)
==7121.44 * 1 + 150*1 + 20*1* (3-1)
=7311.44
--//7321.44+7311.44 = 14632.88
--//取整正好是14633
--//删除索引。
SCOTT@book01p> drop index i_t_a3;
Index dropped.
SCOTT@book01p> drop index i_t_a2;
Index dropped.
SCOTT@book01p> explain plan set statement_id='e4' for select a2 from t where a3 = 50;
Explained.
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where STATEMENT_ID like 'e4';
STATEMENT_ OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------- ------------------------------ ------------------------------ ---------- ---------- ---------- -----
e4 SELECT STATEMENT 3 52486 3 1
e4 TABLE ACCESS FULL 3 52486 3 1
--//谓词比较部分:
--//比较100次,这样比较cost 50*100 = 5000
--//select部分:
7121.44 * blocks + 150*rows + 20*rows* ( Highest_column_id - Lowest_column_id)
=7121.44 * 4 + 150*100 + 20*100* (3-1)
=47485.76
--//47485.76+5000 = 52485.76
--//注意Highest_column_id =3,因为where a3 = 50。
--//重复以前的1个例子:
SCOTT@book01p> explain plan set statement_id='bb' for select a3 from t where a2=100 ;
Explained.
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where STATEMENT_ID='bb';
STATEMENT_ OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------- ---------------- ------- ---- -------- ------- ----
bb SELECT STATEMENT 3 50506 3 1
bb TABLE ACCESS FULL 3 50506 3 1
--//我先说说我的理解然后计算:
--//如果查询时第1条记录是a2=1,这样根本不用取a3字段直接跳过这条记录,这样select部分仅仅取a2后然后比较
--//如果a2=100符合查询条件再取字段a3.有了这样理解cpu cost计算就简单了.
--//select部分,开始仅仅需要取到a2字段(即使select部分包含a3):
7121.44 * blocks + 150*rows + 20*rows* (Highest_column_id - Lowest_column_id)
7121.44 * 4 + 150*100 + 20*rows* ( 2 - 1) = 43485.76 + 2000 = 45486
--//where部分:
比较100次 100*50=5000
仅仅1条符合a2=100.取a3字段成本 :
20*rows* (Highest_column_id - Lowest_column_id)
20*1*(3-2) = 20
--//cpu cost
45486 + 5000+ 20 = 50506
--//完全符合.
--//补充说明:字段成本分2次计算
--//第一次是 20*rows* ( Highest_column - Lowest_column) ,这里的Highest_column=2,Lowest_column=1.rows=100.
--//第二次是 20*rows* ( Highest_column - Lowest_column) ,这里的Highest_column=3,Lowest_column=2.rows=1.
--//总之字段成本要看select以及查询条件结合起来判断,出现的情况可能比较复杂.
6.再补充索引的情况:
--//删除前面建立的索引。
SCOTT@book01p> create index i_t_a3_a2 on t(a3,a2);
Index created.
SCOTT@book01p> explain plan set statement_id='f1' for select a1 from t where a3 = 50;
Explained.
SCOTT@book01p> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where STATEMENT_ID like 'f1%';
STATEMENT_ID OPERATION OPTIONS COST CPU_COST IO_COST TIME
---------------- ------------------------------ ----------------------- ---------- ---------- ---------- -----
f1 SELECT STATEMENT 2 14633 2 1
f1 TABLE ACCESS BY INDEX ROWID BATCHED 2 14633 2 1
f1 INDEX RANGE SCAN 1 7321 1 1
--//分开2部分计算:
--//索引部分:
7121.44 * blocks + 150*rows + 20*rows* (Highest_column_id - Lowest_column_id)
7121.44+150+0 = 7271.44
--//比较1次 50
7271.44+50 = 7321.44
--//注意在索引a3是第1个字段。
--//select部分:
7121.44 * blocks + 150*rows + 20*rows* (Highest_column_id - Lowest_column_id)
7121.44+150+0 = 7271.44
7271.44+7321.44 = 14592.88
--//可以发现我的计算对不上,相差14633-14593 = 40。似乎取到A3字段。
7.总结:
--//首先以上大部分内容完全是先有cpu cost,再反推数值,也许内部的计算更复杂。
--//大概还是存在一些规律:
--//每块的CPU COST X=7121.44。
--//每行的CPU COST Y=150
--//每列的CPU COST Z=20,注意计算Highest_column_id
--//谓词部分使用常量比较成本 A=50 ,引入函数比较成本每个函数的成本不同!!
--//谓词部分使用绑定变量比较成本再增加 100。
--//补充谓词部分字段运算成本,每增加1个字段增加50,增加运算50.
--//扫描唯一索引块成本 1050。
--//在select出现的函数不计算cost。
--//CPU COST计算分成几个部分:
--//扫描块数量的成本
--//扫描行数量的成本
--//扫描字段的成本,取决于字段在段的位置。
--//建议反复看看explain plan set statement_id='bb' for select a3 from t where a2=100 ;的例子
--//可以理解分2部分。
--//谓词比较成本,50起步,增加1个运算增50,增加1个字段增50。注:仅仅是我上面观察到的结果。
--//谓词部分使用绑定变量比较成本再增加 100。
--//索引部分的情况类似,你可以把索引想象为包含索引字段的表,与数据块部分分开计算。
--//特殊的情况是唯一索引扫描,块的成本是1050.