Oracle中利用10053事件来分析Oracle是如何做出最终的执行计划


我们都知道Oracle从10g开始SQL语句选择什么样的执行方式,是全表扫描,还是走索引的依据是执行代价.那么我们怎么可以去看执行代价的信息呢?通过10053事件可以Oracle依据的执行代价和如何做出执行计划的.如果我们发现某一条SQL语句的执行计划和想像的不一样,我们就可以去看看Oracle所使用的统计分析数据是否准确,是不是统计信息太久没有分析了,重新分析有问题的对象,最终让Oracle做出正确的执行计划。

我们来做一次10053事件的示例:

SQL> create table t1 as select rownum rn from dba_objects;
Table created.
SQL> create index ind_t1 on t1(rn);
Index created.
SQL> exec dbms_stats.gather_table_stats(user,'t1',cascade=>true);
PL/SQL procedure successfully completed.
SQL> create table t2 as select rn, 't2' name from t1 where rn <10000;
Table created.
SQL> create index ind_t2 on t2(rn);
Index created.
SQL> exec dbms_stats.gather_table_stats(user,'t2',cascade=>true);
PL/SQL procedure successfully completed.
SQL> alter session set tracefile_identifier='mysession';
Session altered.
SQL> alter session set events '10053 trace name context forever,level 1';
Session altered.
SQL> explain plan for select t2.* from t1,t2 where t1.rn <100 and t1.rn=t2.rn;
Explained.
SQL> alter session set events '10053 trace name context off';
Session altered.
和上次讲SQL_TRACE的时候一样,生成的trace文件的路径是$ORACLE_BASE/admin/SID/udump目录.
与SQL_TRACE和10046事件不同的是,生成的trace文件不能用tkprof处理,只能阅读原始的trace文件.
对trace文件做一个大体的介绍:
**************************
Predicate Move-Around (PM)
**************************
SQL:******* UNPARSED QUERY IS *******
SELECT "T2"."RN" "RN","T2"."NAME" "NAME" FROM "YORKER"."T1" "T1","YORKER"."T2" "T2" WHERE "T1"."RN"<100 AND "T1"."RN"="T2"."RN"
FPD:   Current where clause predicates in SEL$1 (#0) :
         "T1"."RN"<100 AND "T1"."RN"="T2"."RN"
kkogcp: try to generate transitive predicate from check constraints for SEL$1 (#0)
predicates with check contraints: "T1"."RN"<100 AND "T1"."RN"="T2"."RN" AND "T2"."RN"<100
after transitive predicate generation: "T1"."RN"<100 AND "T1"."RN"="T2"."RN" AND "T2"."RN"<100
finally: "T1"."RN"<100 AND "T1"."RN"="T2"."RN" AND "T2"."RN"<100
FPD:   Following transitive predicates are generated in SEL$1 (#0) :
         "T2"."RN"<100
apadrv-start: call(in-use=340, alloc=0), compile(in-use=31192, alloc=0)
kkoqbc-start
            : call(in-use=344, alloc=0), compile(in-use=31976, alloc=0)
******************************************
我们会发现Oracle会对SQL语句做一个转换,把它改成最符合Oracle处理的语句.
比如查询条件变成了 finally: "T1"."RN"<100 AND "T1"."RN"="T2"."RN" AND "T2"."RN"<100
接下来是对一些trace文件中使用的缩写的描述和绑定变量的使用:
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
*******************************************
Peeked values of the binds in SQL statement
*******************************************
接下来是SQL用到的表,索引的统计信息,如果我们发现这个地方和实际不符,可能需要对对象做分析了.
这些信息包括了表的行数,数据块数,行的平均长度.
列平均长度,非重复的值,空值数,密度,最小值和最大值.   
索引的高度,叶子块数目,每一个索引键值占据的块数(LB/K),每一个索引键值对应的表的数据块数目(DB/K).
索引的聚合因子(CLUF).
聚合因子指的是索引中键值在索引块的分布和对应的表中的数据块分布的一种关系.
当索引键值和表中数据排列顺序大致相同时,这个值就越小,当一个索引键值的数据分布在越多的表
的数据块时,这个值越大,意味着使用索引的代价越高.
***************************************
BASE STATISTICAL INFORMATION
***********************
Table Stats::
  Table: T2  Alias: T2
    #Rows: 9999  #Blks:  21  AvgRowLen:  6.00
  Column (#1): RN(NUMBER)
    AvgLen: 4.00 NDV: 9999 Nulls: 0 Density: 1.0001e-004 Min: 1 Max: 9999
Index Stats::
  Index: IND_T2  Col#: 1
    LVLS: 1  #LB: 21  #DK: 9999  LB/K: 1.00  DB/K: 1.00  CLUF: 17.00
***********************
Table Stats::
  Table: T1  Alias: T1
    #Rows: 51060  #Blks:  86  AvgRowLen:  4.00
  Column (#1): RN(NUMBER)
    AvgLen: 5.00 NDV: 51060 Nulls: 0 Density: 1.9585e-005 Min: 5 Max: 51055
Index Stats::
  Index: IND_T1  Col#: 1
    LVLS: 1  #LB: 113  #DK: 51060  LB/K: 1.00  DB/K: 1.00  CLUF: 78.00
***************************************
接下来是对各种访问方式的代价的信息,通过比较所有的数据访问方式的代价,选择代价最小的方式
作为执行计划.
对于T1表,列出了
Access Path: TableScan 全表扫描   Cost:  22.86
Access Path: index (index (FFS)) 索引快速扫描  Cost:  27.63
Access Path: index (IndexOnly)只访问索引.(因为只用到了索引数据RN)   Cost: 2.01
可以看到只访问索引的代价最小.
对于T2表有如下访问方式:(最后会走index (RangeScan))
Access Path: TableScan Cost:  6.37
Access Path: index (RangeScan) Cost: 3.01
然后再是对关联顺序的考虑:
T1关联T2
NL Join(nested loops join) Cost: 2051.15
SM Join(Sort merge join) SM cost: 6.02
HA Join (Hash join) HA cost: 5.52
T2关联T1
NL Join(nested loops join) Cost: 475.12
SM Join(Sort merge join) SM cost: 6.02
HA Join (Hash join) HA cost: 5.52
T1关联T2的CPU代价更小,最后会走T1关联T2.
SINGLE TABLE ACCESS PATH
  Table: T1  Alias: T1    
    Card: Original: 51060  Rounded: 95  Computed: 95.02  Non Adjusted: 95.02
  Access Path: TableScan
    Cost:  22.86  Resp: 22.86  Degree: 0
      Cost_io: 21.00  Cost_cpu: 10824444
      Resp_io: 21.00  Resp_cpu: 10824444
  Access Path: index (index (FFS))
    Index: IND_T1
    resc_io: 26.00  resc_cpu: 9484923
    ix_sel: 0.0000e+000  ix_sel_with_filters: 1
  Access Path: index (FFS)
    Cost:  27.63  Resp: 27.63  Degree: 1
      Cost_io: 26.00  Cost_cpu: 9484923
      Resp_io: 26.00  Resp_cpu: 9484923
  Access Path: index (IndexOnly)
    Index: IND_T1
    resc_io: 2.00  resc_cpu: 33443
    ix_sel: 0.0018609  ix_sel_with_filters: 0.0018609
    Cost: 2.01  Resp: 2.01  Degree: 1
  Best:: AccessPath: IndexRange  Index: IND_T1
         Cost: 2.01  Degree: 1  Resp: 2.01  Card: 95.02  Bytes: 0
***************************************
SINGLE TABLE ACCESS PATH
  Table: T2  Alias: T2    
    Card: Original: 9999  Rounded: 99  Computed: 99.01  Non Adjusted: 99.01
  Access Path: TableScan
    Cost:  6.37  Resp: 6.37  Degree: 0
      Cost_io: 6.00  Cost_cpu: 2151330
      Resp_io: 6.00  Resp_cpu: 2151330
  Access Path: index (RangeScan)
    Index: IND_T2
    resc_io: 3.00  resc_cpu: 58364
    ix_sel: 0.009902  ix_sel_with_filters: 0.009902
    Cost: 3.01  Resp: 3.01  Degree: 1
  Best:: AccessPath: IndexRange  Index: IND_T2
         Cost: 3.01  Degree: 1  Resp: 3.01  Card: 99.01  Bytes: 0
***************************************
OPTIMIZER STATISTICS AND COMPUTATIONS
***************************************
GENERAL PLANS
***************************************
Considering cardinality-based initial join order.
***********************
Join order[1]:  T1[T1]#0  T2[T2]#1
***************
Now joining: T2[T2]#1
***************
NL Join
  Outer table: Card: 95.02  Cost: 2.01  Resp: 2.01  Degree: 1  Bytes: 4
  Inner table: T2  Alias: T2
  Access Path: TableScan
    NL Join:  Cost: 475.12  Resp: 475.12  Degree: 0
      Cost_io: 440.00  Cost_cpu: 204409816
      Resp_io: 440.00  Resp_cpu: 204409816
kkofmx: index filter:"T2"."RN"<100 AND "T1"."RN"<100
  Access Path: index (AllEqJoinGuess)
    Index: IND_T2
    resc_io: 2.00  resc_cpu: 15463
    ix_sel: 1.0001e-004  ix_sel_with_filters: 9.9030e-007
    NL Join (ordered): Cost: 115.77  Resp: 115.77  Degree: 1
      Cost_io: 115.60  Cost_cpu: 950127
      Resp_io: 115.60  Resp_cpu: 950127
  Best NL cost: 115.77
          resc: 115.77 resc_io: 115.60 resc_cpu: 950127
          resp: 115.77 resp_io: 115.60 resp_cpu: 950127
Join Card:  94.08 = outer (95.02) * inner (99.01) * sel (0.01)
Join Card - Rounded: 94 Computed: 94.08
SM Join
  Outer table:
    resc: 2.01  card 95.02  bytes: 4  deg: 1  resp: 2.01
  Inner table: T2  Alias: T2
    resc: 3.01  card: 99.01  bytes: 6  deg: 1  resp: 3.01
    using dmeth: 2  #groups: 1
    SORT resource      Sort statistics
      Sort width:         231 Area size:      202752 Max Area size:    40684544
      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: 5849269
      Total Temp space used: 0
  SM join: Resc: 6.02  Resp: 6.02  [multiMatchCost=0.00]
  SM cost: 6.02
     resc: 6.02 resc_io: 5.00 resc_cpu: 5941076
     resp: 6.02 resp_io: 5.00 resp_cpu: 5941076
HA Join
  Outer table:
    resc: 2.01  card 95.02  bytes: 4  deg: 1  resp: 2.01
  Inner table: T2  Alias: T2
    resc: 3.01  card: 99.01  bytes: 6  deg: 1  resp: 3.01
    using dmeth: 2  #groups: 1
    Cost per ptn: 0.50  #ptns: 1
    hash_area: 0 (max=0)   Hash join: Resc: 5.52  Resp: 5.52  [multiMatchCost=0.00]
  HA cost: 5.52
     resc: 5.52 resc_io: 5.00 resc_cpu: 3025807
     resp: 5.52 resp_io: 5.00 resp_cpu: 3025807
Best:: JoinMethod: Hash
       Cost: 5.52  Degree: 1  Resp: 5.52  Card: 94.08  Bytes: 10
***********************
Best so far: Table#: 0  cost: 2.0057  card: 95.0186  bytes: 380
             Table#: 1  cost: 5.5199  card: 94.0778  bytes: 940
***********************
Join order[2]:  T2[T2]#1  T1[T1]#0
***************
Now joining: T1[T1]#0
***************
NL Join
  Outer table: Card: 99.01  Cost: 3.01  Resp: 3.01  Degree: 1  Bytes: 6
  Inner table: T1  Alias: T1
  Access Path: TableScan
    NL Join:  Cost: 2051.15  Resp: 2051.15  Degree: 0
      Cost_io: 1867.00  Cost_cpu: 1071678304
      Resp_io: 1867.00  Resp_cpu: 1071678304
  Access Path: index (index (FFS))
    Index: IND_T1
    resc_io: 24.74  resc_cpu: 9484923
    ix_sel: 0.0000e+000  ix_sel_with_filters: 1
  Inner table: T1  Alias: T1
  Access Path: index (FFS)
    NL Join:  Cost: 2613.36  Resp: 2613.36  Degree: 0
      Cost_io: 2452.00  Cost_cpu: 939065714
      Resp_io: 2452.00  Resp_cpu: 939065714
kkofmx: index filter:"T1"."RN"<100
  Access Path: index (AllEqJoinGuess)
    Index: IND_T1
    resc_io: 1.00  resc_cpu: 8171
    ix_sel: 1.9585e-005  ix_sel_with_filters: 3.6446e-008
    NL Join (ordered): Cost: 102.15  Resp: 102.15  Degree: 1
      Cost_io: 102.00  Cost_cpu: 872287
      Resp_io: 102.00  Resp_cpu: 872287
  Best NL cost: 102.15
          resc: 102.15 resc_io: 102.00 resc_cpu: 872287
          resp: 102.15 resp_io: 102.00 resp_cpu: 872287
Join Card:  94.08 = outer (99.01) * inner (95.02) * sel (0.01)
Join Card - Rounded: 94 Computed: 94.08
SM Join
  Outer table:
    resc: 3.01  card 99.01  bytes: 6  deg: 1  resp: 3.01
  Inner table: T1  Alias: T1
    resc: 2.01  card: 95.02  bytes: 4  deg: 1  resp: 2.01
    using dmeth: 2  #groups: 1
    SORT resource      Sort statistics
      Sort width:         231 Area size:      202752 Max Area size:    40684544
      Degree:               1
      Blocks to Sort:       1 Row size:           15 Total Rows:             95
      Initial runs:         1 Merge passes:        0 IO Cost / pass:          0
      Total IO sort cost: 0      Total CPU sort cost: 5847820
      Total Temp space used: 0
  SM join: Resc: 6.02  Resp: 6.02  [multiMatchCost=0.00]
  SM cost: 6.02
     resc: 6.02 resc_io: 5.00 resc_cpu: 5939627
     resp: 6.02 resp_io: 5.00 resp_cpu: 5939627
HA Join
  Outer table:
    resc: 3.01  card 99.01  bytes: 6  deg: 1  resp: 3.01
  Inner table: T1  Alias: T1
    resc: 2.01  card: 95.02  bytes: 4  deg: 1  resp: 2.01
    using dmeth: 2  #groups: 1
    Cost per ptn: 0.50  #ptns: 1
    hash_area: 0 (max=0)   Hash join: Resc: 5.52  Resp: 5.52  [multiMatchCost=0.00]
  HA cost: 5.52
     resc: 5.52 resc_io: 5.00 resc_cpu: 3026007
     resp: 5.52 resp_io: 5.00 resp_cpu: 3026007
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.5199  Degree: 1  Card: 94.0000  Bytes: 940
  Resc: 5.5199  Resc_io: 5.0000  Resc_cpu: 3025807
  Resp: 5.5199  Resp_io: 5.0000  Resc_cpu: 3025807
kkoipt: Query block SEL$1 (#0)
******* UNPARSED QUERY IS *******
SELECT "T2"."RN" "RN","T2"."NAME" "NAME" FROM "YORKER"."T1" "T1","YORKER"."T2" "T2" WHERE "T1"."RN"<100 AND "T2"."RN"<100 AND "T1"."RN"="T2"."RN"
kkoqbc-end
          : call(in-use=31732, alloc=0), compile(in-use=33436, alloc=0)
apadrv-end: call(in-use=31732, alloc=0), compile(in-use=34024, alloc=0)
 
sql_id=ar0vn3xs804bs.
Current SQL statement for this session:
explain plan for select t2.* from t1,t2 where t1.rn <100 and t1.rn=t2.rn
 
============
Plan Table
============
------------------------------------------------+-----------------------------------+
| Id  | Operation                     | Name    | Rows  | Bytes | Cost  | Time      |
------------------------------------------------+-----------------------------------+
| 0   | SELECT STATEMENT              |         |       |       |     6 |           |
| 1   |  HASH JOIN                    |         |    94 |   940 |     6 |  00:00:01 |
| 2   |   INDEX RANGE SCAN            | IND_T1  |    95 |   380 |     2 |  00:00:01 |
| 3   |   TABLE ACCESS BY INDEX ROWID | T2      |    99 |   594 |     3 |  00:00:01 |
| 4   |    INDEX RANGE SCAN           | IND_T2  |    99 |       |     2 |  00:00:01 |
------------------------------------------------+-----------------------------------+

相关内容