zoukankan      html  css  js  c++  java
  • 使用hint优化Oracle的运行计划 以及 SQL Tune Advisor的使用

    背景:

    某表忽然出现查询很缓慢的情况。cost 100+ 秒以上;严重影响生产。


    原SQL:

    explain plan for 
    select * from (
    select ID id,RET_NO retNo, FROM_SYS fromSy, TO_SYS toSys, COMMAND_CODE commandCode, COMMAND, STATUS, 
    EXT_CODE, ORIGN_CODE orignCode,error_message errorMessage, RE_F, RET_MSG retMsg 
    from interface_table where ((command_code in('AASSS') 
    			and  status in('F','E') and (re_f = 'N') and FROM_SYS = 'MEE')
    			or (COMMAND_CODE in('XXXX','XXXX9') and FROM_SYS = 'EXT' and RE_F = 'N')
    			) and MOD(id, 1) = 0  order by id) where rownum <= 100  ;
    查看其运行计划:
    SELECT plan_table_output FROM TABLE(DBMS_XPLAN.DISPLAY('PLAN_TABLE'));
    Plan hash value: 1871549687
     
    ----------------------------------------------------------------------------------------------------
    | Id  | Operation                     | Name               | Rows  | Bytes | Cost (%CPU)| Time     |
    ----------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT              |                    |    99 |   382K|   637   (1)| 00:00:08 |
    |*  1 |  COUNT STOPKEY                |                    |       |       |            |          |
    |   2 |   VIEW                        |                    |   100 |   386K|   637   (1)| 00:00:08 |
    |*  3 |    TABLE ACCESS BY INDEX ROWID| INTERFACE_TABLE    |   355 | 55735 |   637   (1)| 00:00:08 |
    |*  4 |     INDEX FULL SCAN           | PK_INTERFACE_TABLE |  1439 |       |   280   (2)| 00:00:04 |
    ----------------------------------------------------------------------------------------------------


    优化后的SQL:

    explain plan for 
    select * from (
    select /*+ index(INT_TABLE IX_INT_TABLE_2)*/ ID id,RET_NO retNo, FROM_SYS fromSy, TO_SYS toSys, COMMAND_CODE commandCode, COMMAND, STATUS, 
    EXT_CODE, ORIGN_CODE orignCode,error_message errorMessage, RE_F, RET_MSG retMsg 
    from interface_table where ((command_code in('AASSS') 
    			and  status in('F','E') and (re_f = 'N') and FROM_SYS = 'MEE')
    			or (COMMAND_CODE in('XXXX','XXXX9') and FROM_SYS = 'EXT' and RE_F = 'N')
    			) and MOD(id, 1) = 0 order by id) where rownum <= 100  ;
    
    查看其运行计划:

    SELECT plan_table_output FROM TABLE(DBMS_XPLAN.DISPLAY('PLAN_TABLE'));
    Plan hash value: 3625182869
     
    --------------------------------------------------------------------------------------------------------
    | Id  | Operation                       | Name                 | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                |                      |    99 |   382K| 19105   (1)| 00:03:50 |
    |*  1 |  COUNT STOPKEY                  |                      |       |       |            |          |
    |   2 |   VIEW                          |                      |   356 |  1376K| 19105   (1)| 00:03:50 |
    |*  3 |    SORT ORDER BY STOPKEY        |                      |   356 | 55892 | 19105   (1)| 00:03:50 |
    |   4 |     CONCATENATION               |                      |       |       |            |          |
    |*  5 |      TABLE ACCESS BY INDEX ROWID| INTERFACE_TABLE      |    69 | 10833 |  9552   (1)| 00:01:55 |
    |*  6 |       INDEX RANGE SCAN          | IX_INTERFACE_TABLE_2 | 77145 |       |    99   (0)| 00:00:02 |
    |*  7 |      TABLE ACCESS BY INDEX ROWID| INTERFACE_TABLE      |   287 | 45059 |  9552   (1)| 00:01:55 |
    |*  8 |       INDEX RANGE SCAN          | IX_INTERFACE_TABLE_2 | 77145 |       |    99   (0)| 00:00:02 |
    --------------------------------------------------------------------------------------------------------
    


    比較:

    查看运行计划。原来是使用 full scan - 当数据量大时很慢。优化后oracle优先走range scan,hint 的 index 是未处理标识字段的索引,正常情况下这个数据集合相对较小--------所以能够达到优化目的。

    详细情况详细分析,我们必需要看实际的表存的业务数据。分析其业务关系找到最小业务集合。后者要看懂运行计划,依据rows, bytes, cost, time 找到最优项目。这个分析顺序不能倒置。

    问题:为何使用 rownum 后,oracle运行计划会走full scan?


    转:怎样看懂运行计划:http://jadethao.iteye.com/blog/1613943


    ====  section2 ====

    http://blog.chinaunix.net/uid-77311-id-3233190.html

    环境:
    OS:Red Hat Linux As 5
    DB:10.2.0.4
     
    Oracle通过STA给出某个SQL运行建议,以下通过一个測试检查Oracle给出的优化建议是否正确.
     
    1.建表并生成測试数据
    SQL> create table tb_test(id number not null,name varchar2(30));
    Table created.
    SQL> create index idx_tb_test on tb_test(id);
    Index created.
    SQL> declare
    begin
      for i in 1 .. 100000 loop
        insert into tb_test values (i, 'test');
        commit;
      end loop;
    end;
    /
     
    2.分析表
    begin
      dbms_stats.gather_table_stats(ownname => 'SCOTT', tabname => 'TB_TEST');
    end;

    3.编造一个运行计划不正确的SQL

    select/*+ full(t)*/ count(1) from scott.tb_test t where t.id=1

    我们知道在ID列上有索引,这个SQL走索引是正确的运行计划,但这里强制oracle走全表扫描,然后通过STA,看oracle给出的运行计划是否正确.

    4.创建TUNING_TASK并运行

    declare
      l_task_name varchar2(30);
      l_sql       clob;
    begin
      l_sql       := 'select/*+ full(t)*/ count(1) from scott.tb_test t where t.id=1';
      l_task_name := DBMS_SQLTUNE.CREATE_TUNING_TASK(sql_text    => l_sql,
                                                     user_name   => 'SCOTT',
                                                     scope       => 'COMPREHENSIVE',
                                                     time_limit  => 60,
                                                     task_name   => 'task_name01',
                                                     description => null);
    dbms_sqltune.Execute_tuning_task(task_name => 'task_name01');
    end;

    5.查看oracle给出的优化建议

    SQL> set serveroutput on;
    SQL> set long 999999999;
    SQL> SELECT DBMS_SQLTUNE.REPORT_TUNING_TASK('task_name01') FROM DUAL;

    DBMS_SQLTUNE.REPORT_TUNING_TASK('TASK_NAME01')
    --------------------------------------------------------------------------------
    GENERAL INFORMATION SECTION
    -------------------------------------------------------------------------------
    Tuning Task Name                  : task_name01
    Tuning Task Owner                 : SYS
    Scope                             : COMPREHENSIVE
    Time Limit(seconds)               : 60
    Completion Status                 : COMPLETED
    Started at                        : 06/03/2012 00:07:58
    Completed at                      : 06/03/2012 00:07:59
    Number of SQL Profile Findings    : 1


    DBMS_SQLTUNE.REPORT_TUNING_TASK('MY_TASK_NAME01')
    --------------------------------------------------------------------------------
    -------------------------------------------------------------------------------
    Schema Name: SCOTT
    SQL ID     : ga3q5tqjgsj5u
    SQL Text   : select/*+ full(t)*/ count(1) from scott.tb_test t where t.id=1

    -------------------------------------------------------------------------------
    FINDINGS SECTION (1 finding)
    -------------------------------------------------------------------------------

    1- SQL Profile Finding (see explain plans section below)
    --------------------------------------------------------

    DBMS_SQLTUNE.REPORT_TUNING_TASK('MY_TASK_NAME01')
    --------------------------------------------------------------------------------
      A potentially better execution plan was found for this statement.

      Recommendation (estimated benefit: 84.11%)
      ------------------------------------------
      - Consider accepting the recommended SQL profile.
        execute dbms_sqltune.accept_sql_profile(task_name => 'task_name01',
                replace => TRUE);

    -------------------------------------------------------------------------------
    EXPLAIN PLANS SECTION
    -------------------------------------------------------------------------------

    DBMS_SQLTUNE.REPORT_TUNING_TASK('TASK_NAME01')
    --------------------------------------------------------------------------------

    1- Original With Adjusted Cost
    ------------------------------
    Plan hash value: 1372292586

    --------------------------------------------------------------------------------

    | Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |

    --------------------------------------------------------------------------------

    -- 当前的运行计划
    DBMS_SQLTUNE.REPORT_TUNING_TASK('TASK_NAME01')
    --------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT   |           |     1 |     4 |     6   (0)| 00:00:01 |

    |   1 |  SORT AGGREGATE    |           |     1 |     4 |            |          |

    |*  2 |   TABLE ACCESS FULL| TB_TEST   |     1 |     4 |     6   (0)| 00:00:01 |

    --------------------------------------------------------------------------------


    Predicate Information (identified by operation id):
    ---------------------------------------------------

    DBMS_SQLTUNE.REPORT_TUNING_TASK('TASK_NAME01')
    --------------------------------------------------------------------------------

       2 - filter("T"."ID"=1)

    -- Oracle给出的运行计划

    2- Using SQL Profile
    --------------------
    Plan hash value: 847665939

    --------------------------------------------------------------------------------
    ---
    | Id  | Operation         | Name          | Rows  | Bytes | Cost (%CPU)| Time
      |

    DBMS_SQLTUNE.REPORT_TUNING_TASK('TASK_NAME01')
    --------------------------------------------------------------------------------
    --------------------------------------------------------------------------------
    ---
    |   0 | SELECT STATEMENT  |               |     1 |     4 |     1   (0)| 00:00:0
    1 |
    |   1 |  SORT AGGREGATE   |               |     1 |     4 |            |
      |
    |*  2 |   INDEX RANGE SCAN| IDX_TB_TEST   |     1 |     4 |     1   (0)| 00:00:0
    1 |
    --------------------------------------------------------------------------------
    ---


    DBMS_SQLTUNE.REPORT_TUNING_TASK('TASK_NAME01')
    --------------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------

       2 - access("T"."ID"=1)

    -------------------------------------------------------------------------------

    从上面的输出能够看出Oracle给出的运行计划是正确的.能够使用例如以下方法使用正确的运行计划

    begin
      dbms_sqltune.accept_sql_profile(task_name => 'task_name01', replace => TRUE);
    end;

    -- The End --




  • 相关阅读:
    ActiveMQ介绍及安装
    Spring注解驱动开发
    Redis 安装、配置、集群
    FastDFS的使用
    How are you vs How are you doing
    阅微草堂笔记
    我在实习的英文表达
    INTRO: THE DAWN (亡灵序曲) 中独白
    银魂的武士道
    Linguistic Data Consortium (LDC)
  • 原文地址:https://www.cnblogs.com/mqxnongmin/p/10746325.html
Copyright © 2011-2022 走看看