Oracle查询优化的最佳方式

时间:2012-06-20 09:23:45

标签: oracle11g

在我的一个项目中,我使用dblink触发了对View的直接查询,但是在执行了性能检查后发现它很昂贵(很多是嵌套循环,高CPU使用)。

现在我们找到了一个解决方案,即使用函数在视图上触发这些查询。这是正确的解决方案还是有更好的方法来执行此操作。

示例查询和绩效报告:

  1. 不使用功能:
  2. 查询:

    SELECT t1.,
           t2.
    FROM   table1 t1
           join table2 t2
             ON t1.id = t2.id
    WHERE  t1.bookingId = '0250014547' 
    

    绩效报告:

    SQL> explain plan for SELECT t1., t2. FROM table1 t1 JOIN table2 t2 ON t1.id = t2.id WHERE t1.bookingId = '0250014547';
    

    SQL> select * from table(dbms_xplan.display);
    
    -------------------------------------------------------------------------------------------
    | Id  | Operation                        | Name                     | Rows  | Bytes | Cost (%CPU)| Time     |
    -------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                 |                          |     1 |   331 |     6   (0)| 00:00:01 |
    |   1 |  NESTED LOOPS                    |                          |     1 |   331 |     6   (0)| 00:00:01 |
    |   2 |   NESTED LOOPS                   |                          |     1 |   299 |     5   (0)| 00:00:01 |
    |   3 |    NESTED LOOPS                  |                          |     1 |   210 |     4   (0)| 00:00:01 |
    |   4 |     NESTED LOOPS                 |                          |     1 |   185 |     3   (0)| 00:00:01 |
    |   5 |      NESTED LOOPS                |                          |     1 |   156 |     2   (0)| 00:00:01 |
    |*  6 |       TABLE ACCESS BY INDEX ROWID| GENERAL_ACCT_MAST_TABLE  |     1 |    66 |     1   (0)| 00:00:01 |
    |*  7 |        INDEX UNIQUE SCAN         | IDX_GAM_FORACID          |     1 |       |     1   (0)| 00:00:01 |
    |   8 |       TABLE ACCESS BY INDEX ROWID| SERVICE_OUTLET_TABLE     |  1694 |   148K|     1   (0)| 00:00:01 |
    |*  9 |        INDEX UNIQUE SCAN         | IDX_SERVICE_OUTLET_TABLE |     1 |       |     1   (0)| 00:00:01 |
    |  10 |      TABLE ACCESS BY INDEX ROWID | GEN_SCHM_PARM_TABLE      |   356 | 10324 |     1   (0)| 00:00:01 |
    |* 11 |       INDEX UNIQUE SCAN          | IDX_GEN_SCHM_PARM_TABLE  |     1 |       |     1   (0)| 00:00:01 |
    |* 12 |     TABLE ACCESS BY INDEX ROWID  | ACCT_STATEMENT_TABLE     |    12M|   309M|     1   (0)| 00:00:01 |
    |* 13 |      INDEX UNIQUE SCAN           | IDX_ACCT_STATEMENT_TABLE |     1 |       |     1   (0)| 00:00:01 |
    |  14 |    TABLE ACCESS BY INDEX ROWID   | CUST_MAST_GEN_TABLE      |    24M|  2119M|     1   (0)| 00:00:01 |
    |* 15 |     INDEX UNIQUE SCAN            | IDX_CUST_MAST_GEN_TABLE  |     1 |       |     1   (0)| 00:00:01 |
    |  16 |   TABLE ACCESS BY INDEX ROWID    | BRANCH_BIC_TABLE         | 65258 |  2039K|     1   (0)| 00:00:01 |
    |* 17 |    INDEX UNIQUE SCAN             | IDX_BRANCH_BIC_TABLE     |     1 |       |     1   (0)| 00:00:01 |
    -------------------------------------------------------------------------------------------
    
    1. 使用功能:
    2. 查询:

      SELECT Funquery1('0250014547')
      FROM   dual; 
      

      绩效报告:

      SQL> explain plan for select gtt('0252050014577') from dual;
      
      SQL> select * from table(dbms_xplan.display);
      
      -----------------------------------------------------------------
      | Id  | Operation        | Name | Rows  | Cost (%CPU)| Time     |
      -----------------------------------------------------------------
      |   0 | SELECT STATEMENT |      |     1 |     2   (0)| 00:00:01 |
      |   1 |  FAST DUAL       |      |     1 |     2   (0)| 00:00:01 |
      -----------------------------------------------------------------
      

2 个答案:

答案 0 :(得分:2)

第二个查询实际上运行得更快吗?

通常,SQL优化器不知道函数内部发生了什么,函数内部的内容不是查询计划的一部分。这意味着您可以隐藏函数内部的大量复杂性,以使查询计划看起来更有效。但是,这并不意味着查询实际上运行得更快,使用更少的CPU,执行更少的I / O操作等。如果您在函数内部使用完全相同的逻辑,则函数执行的查询将与原始查询具有完全相同的计划。除了几个额外的PL / SQL到SQL上下文转换的(次要)开销之外,您将获得相同的性能。

表格的统计数据是否准确?查询计划中的基数估计是否合理地接近现实? t1.bookingId = '0250014547'谓词的选择性如何? bookingID的主键是t1吗?

您的问题文本讨论了数据库链接,但您发布的查询和查询计划似乎都没有引用远程数据库中的对象。您的问题文本讨论了一个视图,但您发布的查询并未引用任何视图。您发布的查询正在加入两个表,查询计划正在加入7.这些不一致通常会使提供任何建议变得更加复杂。

答案 1 :(得分:0)

贾斯汀(+1)完全正确。 EXPLAIN PLAN向您显示对该函数的调用,并没有向您显示该函数内发生的任何事情。

在SQLPlus中,使用

set autotrace on

这将为您提供语句执行的实际统计信息,包括任何递归SQL,它不会显示在EXPLAIN PLAN输出中。

对于更高级的调优,您可以使用Oracle跟踪事件10046.但SQLPlus“autotrace”可能足以满足您的需要。

调整涉及远程数据库上的表/视图的语句(通过DB_LINK)可能很麻烦,因为您必须同时调整您提交的语句和发送到远程数据库的语句。