10053事件
你是否想知道一句sql语句如何执行,它是否走索引,是否采用不同得驱动表,是否用nestloop join,hash join…..?这一切对你是否很神秘呢?或许你会说 execution plan 能看到这些东西,但是你是否清楚 execution plan 是如何得到?这篇文章就是给出了隐藏在 execution plan 底下的具体实现。 幸运的是,现在我们有了这样一种方法,它能10046事件一样,一步一步地将CBO做出的执行计划的整个过程演示给我们看。这个方法就是10053事件,让我们能够直接窥视这里
究竟发生了什么,10053事件依然无法再oracle官方文档上找到任何关于它的信息。
现在让我们来演示如何产生一个10053事件的trace文件
SQL> create table t as select rownum x from dba_objects;
Table created.
SQL> create index ind_t on t(x);
SQL> exec dbms_stats.gather_table_stats(user,'t1',cascade=>true);
PL/SQL procedure successfully completed.
SQL> create table t1 as select x,'T1' name from t where x<10000;
Table created.
SQL> create index ind_t1 on t1(x);
SQL> exec dbms_stats.gather_table_stats(user,'t1',cascade=>true);
SQL> alter session set tracefile_identifier='jscntest53_1';
SQL> alter session set events '10053 trace name context forever,level 1' ;
Session altered.
SQL> explain plan for select t1.* from t,t1 where t.x<100 and t.x=t1.x;
Explained.
SQL> alter session set events '10053 trace name context off';
Session altered.
10053事件的使用方法和10046一样,首先给事件一个级别level,然后运行sql(或者直接使用explain plan的方式产生执行计划),最终终止事件。
在/oracle/ora10/admin/jscn/udump目录我们看到比较特殊的一个trace文件jscn_ora_20033_jscntest53_1.trc,这个就是我们要分析的trace文件
让我一起看看这些内容,10053时间不能tkprof,可以通过该名使trac文件加亮。
[oracle@GD-TEST-84 udump]$ cp jscn_ora_20124_jscntest53_2.trc jscn_ora_20124_jscntest53_2.sql
第一部分
/oracle/ora10/admin/jscn/udump/jscn_ora_20124_jscntest53_2.trc
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
。。。。。。。。。。。。。。。。。
Predicate Move-Around (PM)
这一部分为trace文件通用的,包含了操作系统、数据库和会话的信息,这里不再累述。
从
Predicate Move-Around (PM) 这个开始,进入了10053的trace信息部分,这一部分CBO主要工作是对SQL语句谓词进行分析、重写,把它改写为最符合逻辑的SQL,比如我们最初的谓语
形式(通俗讲就是我们刚开始自己写的where条件):
"T"."X"<100 AND "T"."X"="T1"."X"
被oracle改成了
"T"."X"<100 AND "T"."X"="T1"."X" AND "T1"."X"<100
Predicate Move-Around (PM)
**************************
PM: Considering predicate move-around in SEL$1 (#0).
PM: Checking validity of predicate move-around in SEL$1 (#0).
PM: PM bypassed: Outer query contains no views.
FPD: Considering simple filter push in SEL$1 (#0)
FPD: Current where clause predicates in SEL$1 (#0) :
"T"."X"<100 AND "T"."X"="T1"."X"
kkogcp: try to generate transitive predicate from check constraints for SEL$1 (#0)
predicates with check contraints: "T"."X"<100 AND "T"."X"="T1"."X" AND "T1"."X"<100
after transitive predicate generation: "T"."X"<100 AND "T"."X"="T1"."X" AND "T1"."X"<100
finally:
"T"."X"<100 AND "T"."X"="T1"."X" AND "T1"."X"<100
FPD: Following transitive predicates are generated in SEL$1 (#0) :
"T1"."X"<100
apadrv-start: call(in-use=1064, alloc=16344), compile(in-use=35272, alloc=36536)
kkoqbc-start
: call(in-use=1072, alloc=16344), compile(in-use=36488, alloc=36536)
kkoqbc-subheap (create addr=0x2b297cb0c000)
******************************************
Current SQL statement for this session:
explain plan for select t1.* from t,t1 where t.x<100 and t.x=t1.x
*******************************************
很容易看出,从逻辑上看着两个谓词是等价的,CBO把它改成成这样子,主要是为了更方便计算每一步的成本和估算cardinality(基数),比如我们在这条
sql语句中既要访问t1表中的x例,也要访问那么列,CBO就可以按照这个条件估算没搞操作的结果集(Cardinglity)。
接下来:
*******************************************
Legend
The following abbreviations are used by optimizer trace.
CBQT - cost-based query transformation
JPPD - join predicate push-down
FPD - filter push-down
PM - predicate move-around
CVM - complex view merging
SPJ - select-project-join
SJC - set join conversion
SU - subquery unnesting
OBYE - order by elimination
ST - star transformation
qb - query block
LB - leaf blocks
DK - distinct keys
LB/K - average number of leaf blocks per key
DB/K - average number of data blocks per key
CLUF - clustering factor
NDV - number of distinct values
Resp - response cost
Card - cardinality
Resc - resource cost
NL - nested loops (join)
SM - sort merge (join)
HA - hash (join)
CPUCSPEED - CPU Speed
IOTFRSPEED - I/O transfer speed
IOSEEKTIM - I/O seek time
SREADTIM - average single block read time
MREADTIM - average multiblock read time
MBRC - average multiblock read count
MAXTHR - maximum I/O system throughput
SLAVETHR - average slave I/O throughput
dmeth - distribution method
1: no partitioning required
2: value partitioned
4: right is random (round-robin)
512: left is random (round-robin)
8: broadcast right and partition left
16: broadcast left and partition right
32: partition left using partitioning of right
64: partition right using partitioning of left
128: use hash partitioning dimension
256: use range partitioning dimension
2048: use list partitioning dimension
1024: run the join in serial
0: invalid distribution method
sel - selectivity
ptn - partition
*******************************************
这一部分解释trace文件中用到的一些缩写指标的含义,这些指标在trace文件中被经常使用,所以trace文件开头他们的具体地含义列出来了,以便更加容易的
阅读trace文件头
下一部分是绑定变量的描述:
*******************************************
Peeked values of the binds in SQL statement
*******************************************
如果sql语句中有变量绑定,并且sql语句执行了bind peeking,在这一项中会有相应的信息
接下来部分是一些修复bug信息,以及和性能相关的初始化参数的值,这一部分的内容较多:
***************************************
PARAMETERS USED BY THE OPTIMIZER
********************************
*************************************
PARAMETERS WITH ALTERED VALUES
******************************
_pga_max_size = 490700 KB
*********************************
Bug Fix Control Environment
***************************
fix 4611850 = enabled
fix 4663804 = enabled
fix 4663698 = enabled
fix 4545833 = enabled
。。。。。。。。。。。。。。。。。
*************************************
PARAMETERS WITH DEFAULT VALUES
******************************
optimizer_mode_hinted = false
optimizer_features_hinted = 0.0.0
parallel_execution_enabled = true
parallel_query_forced_dop = 0
parallel_dml_forced_dop = 0
parallel_ddl_forced_degree = 0
parallel_ddl_forced_instances = 0
_query_rewrite_fudge = 90
optimizer_features_enable = 10.2.0.4
_optimizer_search_limit = 5
cpu_count = 24
active_instance_count = 1
parallel_threads_per_cpu = 2
hash_area_size = 131072
。。。。。。。。。。。
*********************************
Bug Fix Control Environment
***************************
fix 4611850 = enabled
fix 4663804 = enabled
fix 4663698 = enabled
fix 4545833 = enabled
fix 3499674 = disabled
fix 4584065 = enabled
fix 4602374 = enabled
fix 4569940 = enabled
fix 4631959 = enabled
fix 4519340 = enabled
fix 4550003 = enabled
fix 4488689 = enabled
***************************************
PARAMETERS IN OPT_PARAM HINT
****************************
***************************************
接下来的一部分是sql语句中引用到的
对象基本信息,包括关联表和各个自索引的信息,这些信息是在相关视图里面可以找到的,比如user_tables,user_indexes,这些值在cbo计算代价的时候
都会被考虑到。
BASE STATISTICAL INFORMATION
***************************************
BASE STATISTICAL INFORMATION
***********************
Table Stats::
Table: T1 Alias: T1 (NOT ANALYZED)
#Rows: 1389 #Blks: 17 AvgRowLen: 100.00
Column (#1): X(NUMBER) NO STATISTICS (using defaults)
AvgLen: 13.00 NDV: 43 Nulls: 0 Density: 0.023038
***********************
Table Stats::
Table: T Alias: T
#Rows: 50741 #Blks: 78 AvgRowLen: 4.00
Column (#1): X(NUMBER)
AvgLen: 5.00 NDV: 50741 Nulls: 0 Density: 1.9708e-05 Min: 6 Max: 50727
Index Stats::
Index: IND_T Col#: 1
LVLS: 1 #LB: 112 #DK: 50741 LB/K: 1.00 DB/K: 1.00 CLUF: 78.00
***************************************
我们看到这里一共列出3个对象的信息,它们分别是T1表,T表,T表的索引IND_T,T表的索引IND_T。
表信息的部分中包括了表的行数、数据块数、平均行数。对于字段,只列出了谓词条件中包含的字段。对于在谓词中没有出现的字段,因为它不影响执行计划的选择,所以以CBO不需要将他考虑到代价中,我们看到,这里列出的是X字段,因为它既是两表关联的字段,同时自身也是一个谓词条件,X列的信息包括了它的类型、平均长度、非重复的值、空值、密度以及列的最大最小值,这些信息在CBO做执行计划代价的计算上都要作为输入的值。
索引项部分中列出了所以的高度,索引页块数(LB,Leaf Blocks),每个索引占据的数据块数(LB/K Leaf Blocks/Key),每个索引键值对应的表中数据块(DB/K,Data Blocks/Key),索引的聚合因子(CLUF,Clustering Factor)。
要注意集合因子
CLUF(索引聚合因子),它表示索引中的键值和元表中的数据分布的一种关系,当索引键值和表中数据的排列顺序大致相同时,它意味着键值指向的数据块越多时(数据排序和索引相差越大)时,这个因子就越大,越不利于索引的使用。了解这个指标对于我们分析sql的执行计划很有用处,比如我们发现SQL执行计划异常,可是从cardinality上无法解释,也许应该考虑一下是否是CLUF的影响导致的。
下面这个例子说明CLUF是如果影响CBO的成本的。
------------------------------------示例开始---------------------------------------------------
SQL> create table t as select object_id,object_name from dba_objects;
Table created.
SQL> create index t_ind on t(object_id) ;
Index created.
SQL> create table t1 as select * from t where rownum=1;
Table created.
SQL> alter table t1 minimize records_per_block; --分布在更多的数据块上
Table altered.
SQL> insert into t1 select * from t;
50659 rows created.
SQL> commit;
Commit complete.
SQL> create index t1_ind on t1(object_id);
Index created.
SQL> exec SYS.DBMS_STATS.GATHER_TABLE_STATS (user,'t',Cascade=> TRUE)
PL/SQL procedure successfully completed.
SQL> exec SYS.DBMS_STATS.GATHER_TABLE_STATS (user,'t1',Cascade=> TRUE);
PL/SQL procedure successfully completed.
SQL> select table_name,num_rows,blocks from user_tables where table_name in ('T','T1');
TABLE_NAME NUM_ROWS BLOCKS
------------------------------ ---------- ----------
T 50659 239
T1 50660 25335
我们创建了两张结构和数据相同的表T和T1,其中T1的数据分布在更多的数据块上
SQL> col TABLE_NAME for a10
SQL> col INDEX_NAME for a20
SQL> col NUM_ROWS for 999999
SQL> col LEAF_BLOCKS for 9999999
SQL> col CLUSTERING_FACTOR for 9999999
SQL> select table_name,index_name,num_rows,leaf_blocks,clustering_factor from user_indexes where table_name in ('T','T1');
TABLE_NAME INDEX_NAME NUM_ROWS LEAF_BLOCKS CLUSTERING_FACTOR
---------- -------------------- -------- ----------- -----------------
T T_IND 50659 112 263
T1 T1_IND 50660 112 25899
我们看到数据分布在数据块上面越多,索引的聚合因子越高,聚合因子的值接近表的数据块的值。
SQL> set autotrace traceonly
SQL> set linesize 200
SQL> select * from t where object_id<100;
98 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1376202287
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 80 | 2240 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T | 80 | 2240 | 3 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T_IND | 80 | | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID"<100)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
17 consistent gets --注意这里
0 physical reads
0 redo size
3051 bytes sent via SQL*Net to client
558 bytes received via SQL*Net from client
8 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
98 rows processed
SQL> select * from t1 where object_id<100;
99 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 2059591622
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 69 | 1932 | 38 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 | 69 | 1932 | 38 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T1_IND | 69 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID"<100)
Statistics
----------------------------------------------------------
150 recursive calls
0 db block gets
106 consistent gets --注意这里
0 physical reads
0 redo size
3061 bytes sent via SQL*Net to client
558 bytes received via SQL*Net from client
8 SQL*Net roundtrips to/from client
4 sorts (memory)
0 sorts (disk)
99 rows processed
我们看到同样的执行计划,索引的聚合因子高的sql(T1)表产生更多的一致性读操作了,执行计划的成本也提高了很多:
对象 一致性读 成本
T 17 3
T1 106 38
上面就是Custering Factor 对CBO计算执行计划的影响。
-----------------------------------------------------示例结束------------------------------------------------------
继续讨论10053事件的trace文件。
接下来部分展示了CBO计算的每个对象单独访问的代价。CBO要计算出每个对象单独访问时的代价,通过比较所有的数据访问的代价
通过比较所有的数据访问的代价,选择出代价最小的一种访问方式。
SINGLE TABLE ACCESS PATH
-----------------------------------------
BEGIN Single Table Cardinality Estimation
-----------------------------------------
Table: T Alias: T
Card: Original: 50741 Rounded: 94 Computed: 94.04 Non Adjusted: 94.04
-----------------------------------------
END Single Table Cardinality Estimation
-----------------------------------------
Access Path: TableScan
Cost: 23.71 Resp: 23.71 Degree: 0
Cost_io: 23.00 Cost_cpu: 10703672
Resp_io: 23.00 Resp_cpu: 10703672
Access Path: index (index (FFS))
Index: IND_T
resc_io: 32.00 resc_cpu: 9423571
ix_sel: 0.0000e+00 ix_sel_with_filters: 1
Access Path: index (FFS)
Cost: 32.63 Resp: 32.63 Degree: 1
Cost_io: 32.00 Cost_cpu: 9423571
Resp_io: 32.00 Resp_cpu: 9423571
Access Path: index (IndexOnly)
Index: IND_T
resc_io: 2.00 resc_cpu: 33243
ix_sel: 0.0018533 ix_sel_with_filters: 0.0018533
Cost: 2.00 Resp: 2.00 Degree: 1
Best:: AccessPath: IndexRange Index: IND_T
Cost: 2.00 Degree: 1 Resp: 2.00 Card: 94.04 Bytes: 0
这里里面的内容比较多,有两个指标对于我们的分析执行计划比较重要:
Card:Original:50741
原纪录数,也就是操作数据源的数据纪录数,在这里就是表的实际纪录50741
Card:Rounded:96
输出的纪录数,CBO计算出通过条件过滤,预计得到的纪录数。我们知道T安装条件小于100的纪录数是99条,这里估算出是96条,比较接近实际值。
通过这一部分的信息我们看到,对于T表,CBO人为可能使用下面几种方式来访问数据。
全表扫描
Access Path: TableScan
Cost: 23.71 Resp: 23.71 Degree: 0
Cost_io: 23.00 Cost_cpu: 10703672
Resp_io: 23.00 Resp_cpu: 10703672
索引快速扫描
Access Path: index (index (FFS)) ----Index fast full scan
单独访问索引:
Access Path: index (IndexOnly)
因为在结果集里面是T1表的信息,所以对于T表,只需要访问索引做关联条件查询,不需要访问表,所以单独访问索引也是可行的。
CBO计算出三种方式产生的代价分别是:
TableScan: 23.71
index (FFS) 32.00
index (IndexOnly) 2.00
很显然,单独访问索引的方式是代价最低的,所以CBO得出的结论,对于T表上的查询,选择使用单独访问索引的方式。
***************************************
SINGLE TABLE ACCESS PATH
-----------------------------------------
BEGIN Single Table Cardinality Estimation
-----------------------------------------
Table: T1 Alias: T1
Card: Original: 9999 Rounded: 99 Computed: 99.01 Non Adjusted: 99.01
-----------------------------------------
END Single Table Cardinality Estimation
-----------------------------------------
Access Path: TableScan
Cost: 6.14 Resp: 6.14 Degree: 0
Cost_io: 6.00 Cost_cpu: 2122844
Resp_io: 6.00 Resp_cpu: 2122844
Access Path: index (RangeScan)
Index: IND_T1
resc_io: 3.00 resc_cpu: 58364
ix_sel: 0.009902 ix_sel_with_filters: 0.009902
Cost: 3.00 Resp: 3.00 Degree: 1
Best:: AccessPath: IndexRange Index: IND_T1
Cost: 3.00 Degree: 1 Resp: 3.00 Card: 99.01 Bytes: 0
***************************************
以上是T1表访问方式的扫描,CBO认为T1表的访问方式有两种:
Access Path: TableScan
Access Path: index (RangeScan)
这两种方式的代价分别是:
TableScan 6.14
RangeScan 3.00
最终CBO计算了买个表单独进行数据访问代价最小的方式,为下一步关系查询提供了代价的计算的数据依据。
下面的部分CBO会列出T,T1表所有的关联方式,并计算出每一种关联方式的代价,最终选择代价最小的关联方式作为sql的执行计划,这里有六种情况:
T关联T1
ENSTED LOOPS JOIN(NL Join)
SORT MERGE JOIN(SM Join)
HASH JOIN(HA Join)
T1关联T
ENSTED LOOPS JOIN(NL Join)
SORT MERGE JOIN(SM Join)
HASH JOIN(HA Join)
以下为这一部分的trace信息:
第一部分 T关联T1
***************************************
OPTIMIZER STATISTICS AND COMPUTATIONS
***************************************
GENERAL PLANS
***************************************
Considering cardinality-based initial join order.
Permutations for Starting Table :0
***********************
Join order[1]: T[T]#0 T1[T1]#1
***************
Now joining: T1[T1]#1
***************
NL Join
Outer table: Card: 82.03 Cost: 2.00 Resp: 2.00 Degree: 1 Bytes: 4
Inner table: T1 Alias: T1
Access Path: TableScan
NL Join: Cost: 392.60 Resp: 392.60 Degree: 1
Cost_io: 381.00 Cost_cpu: 174104090
Resp_io: 381.00 Resp_cpu: 174104090
kkofmx: index filter:"T1"."X"<100 AND "T"."X"<100
Access Path: index (AllEqJoinGuess)
Index: IND_T1
resc_io: 2.00 resc_cpu: 15463
ix_sel: 1.0001e-04 ix_sel_with_filters: 9.9030e-07
NL Join (ordered): Cost: 100.24 Resp: 100.24 Degree: 1
Cost_io: 100.19 Cost_cpu: 823013
Resp_io: 100.19 Resp_cpu: 823013
Best NL cost: 100.24 ------------>ENSTED LOOPS JOIN 方式最好的代价是100.24
resc: 100.24 resc_io: 100.19 resc_cpu: 823013
resp: 100.24 resp_io: 100.19 resp_cpu: 823013
Join Card: 81.22 = outer (82.03) * inner (99.01) * sel (0.01)
Join Card - Rounded: 81 Computed: 81.22
SM Join
Outer table:
resc: 2.00 card 82.03 bytes: 4 deg: 1 resp: 2.00
Inner table: T1 Alias: T1
resc: 3.00 card: 99.01 bytes: 6 deg: 1 resp: 3.00
using dmeth: 2 #groups: 1
SORT resource Sort statistics
Sort width: 1435 Area size: 1048576 Max Area size: 251238400
Degree: 1
Blocks to Sort: 1 Row size: 17 Total Rows: 99
Initial runs: 1 Merge passes: 0 IO Cost / pass: 0
Total IO sort cost: 0 Total CPU sort cost: 15041951
Total Temp space used: 0
SM join: Resc: 6.01 Resp: 6.01 [multiMatchCost=0.00]
SM cost: 6.01 ------------>SORT MERGE JOIN(SM Join) 方式最好的代价是6.01
resc: 6.01 resc_io: 5.00 resc_cpu: 15131158
resp: 6.01 resp_io: 5.00 resp_cpu: 15131158
HA Join
Outer table:
resc: 2.00 card 82.03 bytes: 4 deg: 1 resp: 2.00
Inner table: T1 Alias: T1
resc: 3.00 card: 99.01 bytes: 6 deg: 1 resp: 3.00
using dmeth: 2 #groups: 1
Cost per ptn: 0.50 #ptns: 1
hash_area: 256 (max=61338) Hash join: Resc: 5.51 Resp: 5.51 [multiMatchCost=0.00]
HA cost: 5.51 ------------>HASH JOIN(HA Join) 方式最好的代价是5.51
resc: 5.51 resc_io: 5.00 resc_cpu: 7617598 ------------>并行执行cpu代价7617598
resp: 5.51 resp_io: 5.00 resp_cpu: 7617598
Best:: JoinMethod: Hash ------------>这里计算出最好的代价表连接是Hash
Cost: 5.51 Degree: 1 Resp: 5.51 Card: 81.22 Bytes: 10
***********************
Best so far: Table#: 0 cost: 2.0021 card: 82.0291 bytes: 328
Table#: 1 cost: 5.5074 card: 81.2170 bytes: 810
***********************
第二部分 T1关联T
***********************
Join order[2]: T1[T1]#1 T[T]#0
***************
Now joining: T[T]#0
***************
NL Join
Outer table: Card: 99.01 Cost: 3.00 Resp: 3.00 Degree: 1 Bytes: 6
Inner table: T Alias: T
Access Path: TableScan
NL Join: Cost: 2139.43 Resp: 2139.43 Degree: 1
Cost_io: 2069.00 Cost_cpu: 1057393301
Resp_io: 2069.00 Resp_cpu: 1057393301
Access Path: index (index (FFS))
Index: IND_T
resc_io: 30.34 resc_cpu: 9409631
ix_sel: 0.0000e+00 ix_sel_with_filters: 1
Inner table: T Alias: T
Access Path: index (FFS)
NL Join: Cost: 3069.06 Resp: 3069.06 Degree: 1
Cost_io: 3007.00 Cost_cpu: 931611861
Resp_io: 3007.00 Resp_cpu: 931611861
kkofmx: index filter:"T"."X"<100
Access Path: index (AllEqJoinGuess)
Index: IND_T
resc_io: 1.00 resc_cpu: 8171
ix_sel: 1.9740e-05 ix_sel_with_filters: 3.1964e-08
NL Join (ordered): Cost: 102.06 Resp: 102.06 Degree: 1
Cost_io: 102.00 Cost_cpu: 872287
Resp_io: 102.00 Resp_cpu: 872287
Best NL cost: 102.06 ------------>ENSTED LOOPS JOIN 方式最好的代价是102.06
resc: 102.06 resc_io: 102.00 resc_cpu: 872287
resp: 102.06 resp_io: 102.00 resp_cpu: 872287
Join Card: 81.22 = outer (99.01) * inner (82.03) * sel (0.01)
Join Card - Rounded: 81 Computed: 81.22
SM Join
Outer table:
resc: 3.00 card 99.01 bytes: 6 deg: 1 resp: 3.00
Inner table: T Alias: T
resc: 2.00 card: 82.03 bytes: 4 deg: 1 resp: 2.00
using dmeth: 2 #groups: 1
SORT resource Sort statistics
Sort width: 1435 Area size: 1048576 Max Area size: 251238400
Degree: 1
Blocks to Sort: 1 Row size: 15 Total Rows: 82
Initial runs: 1 Merge passes: 0 IO Cost / pass: 0
Total IO sort cost: 0 Total CPU sort cost: 15035869
Total Temp space used: 0
SM join: Resc: 6.01 Resp: 6.01 [multiMatchCost=0.00]
SM cost: 6.01 ------------>SORT MERGE JOIN(SM Join) 方式最好的代价是6.01
resc: 6.01 resc_io: 5.00 resc_cpu: 15125076
resp: 6.01 resp_io: 5.00 resp_cpu: 15125076
HA Join
Outer table:
resc: 3.00 card 99.01 bytes: 6 deg: 1 resp: 3.00
Inner table: T Alias: T
resc: 2.00 card: 82.03 bytes: 4 deg: 1 resp: 2.00
using dmeth: 2 #groups: 1
Cost per ptn: 0.50 #ptns: 1
hash_area: 256 (max=61338) Hash join: Resc: 5.51 Resp: 5.51 [multiMatchCost=0.00]
HA cost: 5.51 ------------>HASH JOIN(HA Join) 方式最好的代价是5.51
resc: 5.51 resc_io: 5.00 resc_cpu: 7618448 ------------>并行执行cpu代价 7618448 高于 上一种表连接方式的(7617598)
resp: 5.51 resp_io: 5.00 resp_cpu: 7618448
Join order aborted: cost > best plan cost
***********************
(newjo-stop-1) k:0, spcnt:0, perm:2, maxperm:2000
*********************************
Number of join permutations tried: 2
*********************************
(newjo-save) [1 0 ]
Final - All Rows Plan: Best join order: 1 ------------>第一种关联顺序
Cost: 5.5074 Degree: 1 Card: 81.0000 Bytes: 810
Resc: 5.5074 Resc_io: 5.0000 Resc_cpu: 7617598
Resp: 5.5074 Resp_io: 5.0000 Resc_cpu: 7617598
kkoipt: Query block SEL$1 (#0)
******* UNPARSED QUERY IS *******
SELECT "T1"."X" "X","T1"."NAME" "NAME" FROM "SYS"."T" "T","SYS"."T1" "T1" WHERE "T"."X"<100 AND "T1"."X"<100 AND "T"."X"="T1"."X"
kkoqbc-subheap (delete addr=0x2b4f6501c000, in-use=24512, alloc=26368)
集中关联方式的代价如下:
T关联T1 代价
ENSTED LOOPS JOIN(NL Join) 100.24
SORT MERGE JOIN(SM Join) 6.01
HASH JOIN(HA Join) 5.51
T1关联T
ENSTED LOOPS JOIN(NL Join) 102.06
SORT MERGE JOIN(SM Join) 6.01
HASH JOIN(HA Join) 5.51
尽管两种关联顺序里面的Hash Join的代价都是一样的
5.51,但是第一个表关联的顺序的
resc_cpu的代价要小,索引CBO最终选择了第一个表关联顺序的下的HASH JOIN
方式作为最终的执行计划,即T关联T1通过Hash Join的方式来做关联的代价最小。
下面这个部分是通过CBO给出的一个执行计划报告,其中ROWS例对应于上面每个操作的 cardinality rounded cost 对应于每一个操作的cost值。
============
Plan Table
============
------------------------------------------------+-----------------------------------+
| Id | Operation | Name | Rows | Bytes | Cost | Time |
------------------------------------------------+-----------------------------------+
| 0 | SELECT STATEMENT | | | | 6 | |
| 1 | HASH JOIN | | 81 | 810 | 6 | 00:00:01 |
| 2 | INDEX RANGE SCAN | IND_T | 82 | 328 | 2 | 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID | T1 | 99 | 594 | 3 | 00:00:01 |
| 4 | INDEX RANGE SCAN | IND_T1 | 99 | | 2 | 00:00:01 |
------------------------------------------------+-----------------------------------+
Predicate Information:
----------------------
1 - access("T"."X"="T1"."X")
2 - access("T"."X"<100)
4 - access("T1"."X"<100)
Content of other_xml column
===========================
db_version : 10.2.0.4
parse_schema : SYS
plan_hash : 2145127414
Outline Data:
通过一系列的计算和比较,CBO最终选择了上面的执行计划作为SQL的最终执行计划。trace文件最后,这里不做讨论。
下面是帮一个网友看的一个问题
这个是测试环境,走索引的
SINGLE TABLE ACCESS PATH
Single Table Cardinality Estimation for CLAIMS[CLAIMS]
Table: CLAIMS Alias: CLAIMS
Card: Original: 100817.000000 Rounded: 6470 Computed: 6469.52 Non Adjusted: 6469.52
Access Path: TableScan
Cost: 2845.00 Resp: 2845.00 Degree: 0
Cost_io: 2805.00 Cost_cpu: 662177710
Resp_io: 2805.00 Resp_cpu: 662177710
Access Path: index (RangeScan)
Index: CLAIMS_IDX16
resc_io: 6904.60 resc_cpu: 275804847
ix_sel: 0.333333 ix_sel_with_filters: 0.333333
Cost: 6921.26 Resp: 6921.26 Degree: 1
Access Path: index (RangeScan)
Index: CLAIMS_IDX30
resc_io: 3346.60 resc_cpu: 171975781
ix_sel: 0.500000 ix_sel_with_filters: 0.500000
Cost: 3356.98 Resp: 3356.98 Degree: 1
****** trying bitmap/domain indexes ******
Access Path: index (AllEqRange)
Index: CLAIMS_IDX16
resc_io: 46.00 resc_cpu: 3689036
ix_sel: 0.166667 ix_sel_with_filters: 0.166667
Cost: 46.22 Resp: 46.22 Degree: 0
Access Path: index (AllEqRange)
Index: CLAIMS_IDX16
resc_io: 46.00 resc_cpu: 3689036
ix_sel: 0.166667 ix_sel_with_filters: 0.166667
Cost: 46.22 Resp: 46.22 Degree: 0
Access Path: index (AllEqRange)
Index: CLAIMS_IDX30
resc_io: 33.00 resc_cpu: 2589658
ix_sel: 0.250000 ix_sel_with_filters: 0.250000
Cost: 33.16 Resp: 33.16 Degree: 0
Access Path: index (AllEqRange)
Index: CLAIMS_IDX30
resc_io: 33.00 resc_cpu: 2589658
ix_sel: 0.250000 ix_sel_with_filters: 0.250000
Cost: 33.16 Resp: 33.16 Degree: 0
Access path: Bitmap index - accepted
Cost: 2730.185047 Cost_io: 2721.380943 Cost_cpu: 145743285.440609 Sel: 0.166667
Not Believed to be index-only
****** finished trying bitmap/domain indexes ******
******** Begin index join costing ********
******** End index join costing ********
Best:: AccessPath: IndexBitmap
Cost: 2730.19 Degree: 1 Resp: 2730.19 Card: 6469.52 Bytes: 0
这个是真实环境,不走索引
SINGLE TABLE ACCESS PATH
Single Table Cardinality Estimation for CLAIMS[CLAIMS]
Table: CLAIMS Alias: CLAIMS
Card: Original: 101522.000000 Rounded: 6570 Computed: 6570.11 Non Adjusted: 6570.11
Access Path: TableScan
Cost: 5949.01 Resp: 5949.01 Degree: 0
Cost_io: 5900.00 Cost_cpu: 811350733
Resp_io: 5900.00 Resp_cpu: 811350733
Access Path: index (RangeScan)
Index: CLAIMS_IDX16
resc_io: 39801.47 resc_cpu: 514492135
ix_sel: 0.333333 ix_sel_with_filters: 0.333333
Cost: 39832.55 Resp: 39832.55 Degree: 1
Access Path: index (RangeScan)
Index: CLAIMS_IDX30
resc_io: 25940.30 resc_cpu: 344175912
ix_sel: 0.500000 ix_sel_with_filters: 0.500000
Cost: 25961.09 Resp: 25961.09 Degree: 1
Best:: AccessPath: TableScan
Cost: 5949.01 Degree: 1 Resp: 5949.01 Card: 6570.11 Bytes: 0