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的成本的。
------------------------------------示例开始---------------------------------------------------
我们创建了两张结构和数据相同的表T和T1,其中T1的数据分布在更多的数据块上
我们看到数据分布在数据块上面越多,索引的聚合因子越高,聚合因子的值接近表的数据块的值。
上面就是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
第二部分 T1关联T
尽管两种关联顺序里面的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