zoukankan      html  css  js  c++  java
  • Oracle SQL性能分析之10053事件

    Oracle SQL性能分析之10053事件

    [日期:2019-03-19] 来源:Linux社区  作者:Linux [字体:  ]
     

    优化器生成正确执行计划的前提条件是要有正确的统计信息,不准确的统计信息往往会导致错误的执行计划。当通过SQL和基数推断出的执行计划和实际执行计划不同时,就可以借助10053事件。10053事件是用来诊断优化器如何估算成本和选择执行计划的,用它产生的trace文件提供了Oracle如何选择执行计划,为什么会得到这样的执行计划信息。和10046事件类似,它主要用于特殊情况下的分析和诊断。

    1、测试环境:
    SQL> select * from v$version;
    BANNER
    ----------------------------------------------------------------------
    Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production

    2、建立测试对象
    SQL> create table tabtemp as select * from dba_objects where object_id is not null;
    Table created.

    SQL> select count(object_id) from tabtemp;
    COUNT(OBJECT_ID)
    ----------------
              72764

    测试表object_id列的数值分布:
    SQL> select count(distinct object_id) from tabtemp;
    COUNT(DISTINCTOBJECT_ID)
    ------------------------
                      72764
    建立索引:
    SQL> create index idx_tabtemp_id on tabtemp(object_id);

    3、生成10053事件
    统计表及索引信息:
    SQL> exec dbms_stats.gather_table_stats(user,'TABTEMP',cascade=>true);

    查看执行计划:
    SQL> alter session set tracefile_identifier='plan';
    SQL> set autotrace trace exp;
    SQL> alter session set events '10053 trace name context forever,level 1';

    SQL> select * from tabtemp where object_id=3;
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 2221486709
    --------------------------------------------------------------------------------------------
    | Id  | Operation                  | Name          | Rows  | Bytes | Cost (%CPU)| Time    |
    --------------------------------------------------------------------------------------------
    |  0 | SELECT STATEMENT            |                |    1 |    97 |    2  (0)| 00:00:01 |
    |  1 |  TABLE ACCESS BY INDEX ROWID| TABTEMP        |    1 |    97 |    2  (0)| 00:00:01 |
    |*  2 |  INDEX RANGE SCAN          | IDX_TABTEMP_ID |    1 |      |    1  (0)| 00:00:01 |
    -------------------------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
      2 - access("OBJECT_ID"=3)
    由执行计划可知,查询走索引,这是非常高效的查询方式。


    更新测试表,将object_id列数值全部设置为3:
    SQL> update tabtemp set object_id=3 where object_id!=3;
    72763 rows updated.

    SQL> commit;
    SQL> select count(distinct object_id) from tabtemp;
    COUNT(DISTINCTOBJECT_ID)
    ------------------------
                          1

    不收集统计数据,查看执行计划:
    SQL> set autotrace trace exp;
    SQL> select * from tabtemp where object_id=3;
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 2221486709
    -------------------------------------------------------------------------------------------
    | Id  | Operation                  | Name          | Rows  | Bytes | Cost (%CPU)| Time    |
    -------------------------------------------------------------------------------------------
    |  0 | SELECT STATEMENT            |                |    1 |    97 |    2  (0)| 00:00:01 |
    |  1 |  TABLE ACCESS BY INDEX ROWID| TABTEMP        |    1 |    97 |    2  (0)| 00:00:01 |
    |*  2 |  INDEX RANGE SCAN          | IDX_TABTEMP_ID |    1 |      |    1  (0)| 00:00:01 |
    -------------------------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
      2 - access("OBJECT_ID"=3)
    由输出结果可知,本次查询沿用原来的执行计划,是错误的执行计划。

    重新对更新后的测试对象进行数据分析:
    SQL> set autotrace off;
    SQL> exec dbms_stats.gather_table_stats(user,'TABTEMP',cascade=>true);

    查看收集统计数据后的执行计划:
    SQL> set autotrace trace exp;
    SQL> select * from tabtemp where object_id=3;
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 3955501171
    -----------------------------------------------------------------------------
    | Id  | Operation        | Name    | Rows  | Bytes | Cost (%CPU)| Time    |
    -----------------------------------------------------------------------------
    |  0 | SELECT STATEMENT  |        | 72757 |  6749K|  293  (2)| 00:00:04 |
    |*  1 |  TABLE ACCESS FULL| TABTEMP | 72757 |  6749K|  293  (2)| 00:00:04 |
    -----------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
      1 - filter("OBJECT_ID"=3)

    由输出可知,本次查询使用了正确的执行计划。所以,要注意在实际生产环境中对表、索引等进行及时有效的统计数据收集工作,避免因此带来性能问题。

    SQL> alter session set events '10053 trace name context off';
    SQL> select value from v$diag_info where name='Default Trace File';
    VALUE
    ------------------------------------------------------------------------------
    c:\app\administrator\diag\rdbms\orcl11g\orcl11g\trace\orcl11g_ora_5952_plan.trc


    4、分析10053事件trace文件中CBO出错的位置
    #more  orcl11g_ora_5952_plan.trc
    在前面模拟中有如下操作:
    SQL> update tabtemp set object_id=3 where object_id!=3;
    72763 rows updated.
    SQL> commit;
    SQL> select count(distinct object_id) from tabtemp;
    COUNT(DISTINCTOBJECT_ID)
    ------------------------
                          1
    SQL> select * from tabtemp where object_id=3;  此处没有重新进行统计信息收集,直接发起查询。

    查看10053trace文件中相对应的内容:

    ***************************************

    BASE STATISTICAL INFORMATION

    ***********************

    Table Stats::

      Table: TABTEMP  Alias: TABTEMP

        #Rows: 72764  #Blks:  1062  AvgRowLen:  97.00

    Index Stats::

      Index: IDX_TABTEMP_ID  Col#: 4

    LVLS: 1  #LB: 161  #DK: 72764 LB/K: 1.00  DB/K: 1.00  CLUF: 1102.00

    Access path analysis for TABTEMP

    ***************************************

    SINGLE TABLE ACCESS PATH

      Single Table Cardinality Estimation for TABTEMP[TABTEMP]

      Table: TABTEMP  Alias: TABTEMP

        Card: Original: 72764.000000  Rounded: 1  Computed: 1.00  Non Adjusted: 1.00

      Access Path: TableScan

        Cost:  291.18  Resp: 291.18  Degree: 0

          Cost_io: 289.00  Cost_cpu: 26481829

          Resp_io: 289.00  Resp_cpu: 26481829

      Access Path: index (AllEqRange)

        Index: IDX_TABTEMP_ID

        resc_io: 2.00  resc_cpu: 15723

        ix_sel: 0.000014  ix_sel_with_filters: 0.000014

        Cost: 2.00  Resp: 2.00  Degree: 1

      Best:: AccessPath: IndexRange

      Index: IDX_TABTEMP_ID

            Cost: 2.00  Degree: 1  Resp: 2.00  Card: 1.00  Bytes: 0

    ***************************************

    如上述输出trace文件中加粗所示:

    #DK: 表示索引中不同的键值数量。此处数值72764错误,在对表进行更新后,索引中只有1个key。

    LB/K:表示每个键值对应多少个leaf blocks。此处数值为1错误,应为leaf blocks即#LB的数值。

    DB/K:表示每个key对应多少个数据块。此处数值为1错误,应为#Blks的数值。

    Rounded:表示关联后将产生多少条数据。此处数值为1错误,应该是测试表的总行数72764。

    ix_sel_with_filters 是带有过滤条件的索引选择率,即过滤因子FF,ix_sel_with_filters =1/DK ,本例中DK数值为1,所以ix_sel_with_filters数值近似为1。

    Card:即Cardinality,10gr2以后cardinality用rows表示,是oracle自己估算的数值。本例中应为测试表的行数。

    本例中Index range scan访问方式cost计算公式为:

    cost=blevel + FF*leaf_blocks + FF*clustering_factor,由于FF(ix_sel_with_filters)数值出现的巨大差异(错误的数值为0.000014,正确数值近似等于1),导致Index range scan访问方式cost数值出现严重偏差,最终生成了错误的执行计划。

  • 相关阅读:
    (floyd+DP) zoj 3027
    (树形DP) acdream 1028
    acdream 1032
    (BFS) acdream 1191
    (树形DP) bzoj 1060
    (状态压缩DP) poj 2978
    (DP) codeforces 358D
    (DP+二分) hdu 3433
    (最大生成树) hdu 3367
    hdoj 3501
  • 原文地址:https://www.cnblogs.com/yaoyangding/p/15591170.html
Copyright © 2011-2022 走看看