• 系统设计时应尽量避免出现left outer join, right outer join


    今天盖尔找我优化一条SQL,SQL如下:

    SELECT  DISTINCT b.organ_id,
                            c.company_name as organ_name,
                            a.distri_date,
                            a.distri_type,
                            d.TYPE_NAME Capital_name,
                            b.policy_code,
                            b.apply_code send_code,
                            i.ATTRIBUTE10 total_code,
                            f.pay_mode,
                            j.type_name as policy_type_name,
                            e.Internal_Id AS product_code,
                            round(a.distri_amount, 2) AS fee_amount,
                            decode(a.posted,
                                   'Y',
                                   to_char(i.transaction_date, 'yyyy-mm-dd'),
                                   to_char(a.distri_date, 'yyyy-mm-dd')) As finish_time,
                            F.DR_SEG1,
                            F.DR_SEG2,
                            F.DR_SEG3,
                            F.DR_SEG4,
                            F.DR_SEG5,
                            F.DR_SEG6,
                            f.dr_seg7,
                            f.dr_seg8,
                            f.dr_seg9,
                            f.dr_seg10,
                            f.cr_seg1,
                            f.cr_seg2,
                            f.cr_seg3,
                            f.cr_seg4,
                            f.cr_seg5,
                            f.cr_seg6,
                            f.cr_seg7,
                            f.cr_seg8,
                            f.cr_seg9,
                            f.cr_seg10,
                            f.je_posting_id as cred_id
              FROM T_CAPITAL_DISTRIBUTE a,
                   t_contract_master b,
                   t_channel_type j,
                   t_company_organ c,
                   t_capital_distri_type d,
                   t_product_life e,
                   t_contract_product f,
                   (select * from T_BIZ_ACCOUNTING_INFO where DATA_TABLE = '7') F,
                   T_GL_BIZ_INTERFACE i,
                   (select  organ_id
                      from t_company_organ
                     start with organ_id = '101'
                    connect by parent_id = prior organ_id) o
             WHERE a.policy_id = b.policy_id
               and a.item_id = f.item_id(+)
               AND b.organ_id = c.Organ_Id
               AND a.distri_type = d.distri_type
               AND a.product_id = e.product_id
               and b.policy_type = j.INDIVIDUAL_GROUP
               AND A.capital_id = F.FEE_ID(+)
               AND A.cred_id = i.posting_id(+)
               and a.organ_id = i.segment1(+)
               and nvl(a.posted, 'N') = 'Y'
               and a.cred_id = 493997
               and i.transaction_date >= to_date('2011-11-01', 'yyyy-MM-dd')
               and i.transaction_date < to_date('2011-11-30', 'yyyy-MM-dd') + 1
               and a.distri_type = i.reference3(+)
               and i.segment1 = o.organ_id(+);


    盖尔说这个SQL逻辑读有2千万,跑300s,返回9000条数据,SQL 执行计划如下:

    SQL> select * from table(dbms_xplan.display);
    
    PLAN_TABLE_OUTPUT
    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    -------------------------------------------------------------------------------------------------------------
    | Id  | Operation                             |  Name                          | Rows  | Bytes | Cost (%CPU)|
    -------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                      |                                |     1 |   356 |    27   (0)|
    |   1 |  SORT UNIQUE                          |                                |     1 |   356 |    27   (0)|
    |*  2 |   HASH JOIN OUTER                     |                                |     1 |   356 |    12   (9)|
    |   3 |    NESTED LOOPS                       |                                |     1 |   350 |    10  (10)|
    |   4 |     NESTED LOOPS                      |                                |     1 |   338 |     9  (12)|
    |   5 |      NESTED LOOPS OUTER               |                                |     1 |   302 |     8  (13)|
    |   6 |       NESTED LOOPS                    |                                |     1 |   171 |     7  (15)|
    |   7 |        NESTED LOOPS                   |                                |     1 |   125 |     6  (17)|
    |   8 |         NESTED LOOPS                  |                                |     1 |   100 |     5  (20)|
    |   9 |          NESTED LOOPS OUTER           |                                |     1 |    86 |     4  (25)|
    |  10 |           NESTED LOOPS                |                                |     1 |    76 |     3  (34)|
    |  11 |            TABLE ACCESS BY INDEX ROWID| T_GL_BIZ_INTERFACE             |     1 |    24 |     2  (50)|
    |* 12 |             INDEX SKIP SCAN           | IDX10                          |     1 |       |     3   (0)|
    |* 13 |            TABLE ACCESS BY INDEX ROWID| T_CAPITAL_DISTRIBUTE           |     1 |    52 |     2  (50)|
    |* 14 |             INDEX RANGE SCAN          | IDX_CAPITAL_DISTR__CRED_ORGAN  |    15 |       |     2   (0)|
    |  15 |           TABLE ACCESS BY INDEX ROWID | T_CONTRACT_PRODUCT             |     1 |    10 |     2  (50)|
    |* 16 |            INDEX UNIQUE SCAN          | PK_T_CONTRACT_PRODUCT          |     1 |       |     1   (0)|
    |  17 |          TABLE ACCESS BY INDEX ROWID  | T_PRODUCT_LIFE                 |     1 |    14 |     2  (50)|
    |* 18 |           INDEX UNIQUE SCAN           | PK_T_PRODUCT_LIFE              |     1 |       |            |
    |  19 |         TABLE ACCESS BY INDEX ROWID   | T_CAPITAL_DISTRI_TYPE          |     1 |    25 |     2  (50)|
    |* 20 |          INDEX UNIQUE SCAN            | PK_T_CAPITAL_DISTRI_TYPE       |     1 |       |            |
    |  21 |        TABLE ACCESS BY INDEX ROWID    | T_CONTRACT_MASTER              |     1 |    46 |     2  (50)|
    |* 22 |         INDEX UNIQUE SCAN             | PK_T_CONTRACT_MASTER           |     1 |       |     1   (0)|
    |  23 |       TABLE ACCESS BY INDEX ROWID     | T_BIZ_ACCOUNTING_INFO          |     1 |   131 |     2  (50)|
    |* 24 |        INDEX RANGE SCAN               | IDX_BIZ_ACCOUNTING_INFO__FEE_  |     1 |       |     2   (0)|
    |  25 |      TABLE ACCESS BY INDEX ROWID      | T_COMPANY_ORGAN                |     1 |    36 |     2  (50)|
    |* 26 |       INDEX UNIQUE SCAN               | PK_T_COMPANY_ORGAN             |     1 |       |            |
    |  27 |     TABLE ACCESS BY INDEX ROWID       | T_CHANNEL_TYPE                 |     1 |    12 |     2  (50)|
    |* 28 |      INDEX UNIQUE SCAN                | PK_T_CHANNEL_TYPE              |     1 |       |            |
    |  29 |    VIEW                               |                                |     7 |    42 |            |
    |* 30 |     CONNECT BY WITH FILTERING         |                                |       |       |            |
    |  31 |      NESTED LOOPS                     |                                |       |       |            |
    |* 32 |       INDEX UNIQUE SCAN               | PK_T_COMPANY_ORGAN             |     1 |     6 |            |
    |  33 |       TABLE ACCESS BY USER ROWID      | T_COMPANY_ORGAN                |       |       |            |
    |  34 |      NESTED LOOPS                     |                                |       |       |            |
    |  35 |       BUFFER SORT                     |                                |     7 |    70 |            |
    |  36 |        CONNECT BY PUMP                |                                |       |       |            |
    |* 37 |       INDEX RANGE SCAN                | T_COMPANY_ORGAN_IDX_002        |     7 |    70 |     1   (0)|
    -------------------------------------------------------------------------------------------------------------
    
       2 - access("I"."SEGMENT1"="O"."ORGAN_ID"(+))
      12 - access("I"."TRANSACTION_DATE">=TO_DATE('2011-11-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss') AND
                  "I"."POSTING_ID"=493997 AND "I"."TRANSACTION_DATE"<TO_DATE('2011-12-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss'))
           filter("I"."POSTING_ID"=493997)
      13 - filter("A"."DISTRI_TYPE"="I"."REFERENCE3")
      14 - access("A"."CRED_ID"=493997 AND "A"."ORGAN_ID"="I"."SEGMENT1")
           filter(NVL("A"."POSTED",'N')='Y')
      16 - access("A"."ITEM_ID"="F"."ITEM_ID"(+))
      18 - access("A"."PRODUCT_ID"="E"."PRODUCT_ID")
      20 - access("A"."DISTRI_TYPE"="D"."DISTRI_TYPE")
      22 - access("A"."POLICY_ID"="B"."POLICY_ID")
      24 - access("A"."CAPITAL_ID"="T_BIZ_ACCOUNTING_INFO"."FEE_ID"(+) AND
                  "T_BIZ_ACCOUNTING_INFO"."DATA_TABLE"(+)=7)
      26 - access("B"."ORGAN_ID"="C"."ORGAN_ID")
      28 - access("B"."POLICY_TYPE"="J"."INDIVIDUAL_GROUP")
      30 - filter("T_COMPANY_ORGAN"."ORGAN_ID"='101')
      32 - access("T_COMPANY_ORGAN"."ORGAN_ID"='101')
      37 - access("T_COMPANY_ORGAN"."PARENT_ID"=NULL)
    
    65 rows selected.


    从执行计划上去看,这个SQL基本上没有技术上可以进一步优化的地方了,你可能会说这里不应该走INDEX SKIP SCAN ,应该走INDEX RANGE SCAN

    但是这个都是小问题,它不是决定性因素,SQL 优化从技术上 不可行之后,就应该立马分析业务,请仔细观察这个SQL

    它有很多的外连接,外连接很特殊,因为外连接的驱动表的顺序是固定的 比如

    a left join b 那么 a就只能做驱动表(不管是走nested loops outer 或者hash join outer) 你没办法更改驱动表的顺序,哪怕你用leading ,order hint都不行

    正是因为这个SQL里面有很多外连接,SQL的访问顺序给固定死了,所以没办法从技术上调优SQL了

    我让盖尔把外连接的(+) 去掉,跑一下SQL ,SQL只需要30秒就能跑完 ,执行计划如下

    ----------------------------------------------------------------------------------------------------------------
    | Id  | Operation                                |  Name                          | Rows  | Bytes | Cost (%CPU)|
    ----------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                         |                                |     1 |   354 |    27   (0)|
    |   1 |  SORT UNIQUE                             |                                |     1 |   354 |    27   (0)|
    |   2 |   TABLE ACCESS BY INDEX ROWID            | T_BIZ_ACCOUNTING_INFO          |     1 |   131 |     2  (50)|
    |   3 |    NESTED LOOPS                          |                                |     1 |   354 |    12   (9)|
    |   4 |     NESTED LOOPS                         |                                |     1 |   223 |    11  (10)|
    |   5 |      NESTED LOOPS                        |                                |     1 |   209 |    10  (10)|
    |   6 |       NESTED LOOPS                       |                                |     1 |   199 |     9  (12)|
    |   7 |        NESTED LOOPS                      |                                |     1 |   174 |     8  (13)|
    |   8 |         NESTED LOOPS                     |                                |     1 |   138 |     7  (15)|
    |   9 |          NESTED LOOPS                    |                                |     1 |   126 |     6  (17)|
    |* 10 |           HASH JOIN                      |                                |     1 |    80 |     5  (20)|
    |  11 |            TABLE ACCESS BY INDEX ROWID   | T_CAPITAL_DISTRIBUTE           |     1 |    50 |     2  (50)|
    |  12 |             NESTED LOOPS                 |                                |     1 |    74 |     3  (34)|
    |  13 |              TABLE ACCESS BY INDEX ROWID | T_GL_BIZ_INTERFACE             |     1 |    24 |     2  (50)|
    |* 14 |               INDEX SKIP SCAN            | IDX10                          |     1 |       |     3   (0)|
    |* 15 |              INDEX RANGE SCAN            | IDX14                          |     1 |       |     2   (0)|
    |  16 |            VIEW                          |                                |     7 |    42 |            |
    |* 17 |             FILTER                       |                                |       |       |            |
    |* 18 |              CONNECT BY WITH FILTERING   |                                |       |       |            |
    |  19 |               NESTED LOOPS               |                                |       |       |            |
    |* 20 |                INDEX UNIQUE SCAN         | PK_T_COMPANY_ORGAN             |     1 |     6 |            |
    |  21 |                TABLE ACCESS BY USER ROWID| T_COMPANY_ORGAN                |       |       |            |
    |  22 |               NESTED LOOPS               |                                |       |       |            |
    |  23 |                BUFFER SORT               |                                |     7 |    70 |            |
    |  24 |                 CONNECT BY PUMP          |                                |       |       |            |
    |* 25 |                INDEX RANGE SCAN          | T_COMPANY_ORGAN_IDX_002        |     7 |    70 |     1   (0)|
    |  26 |           TABLE ACCESS BY INDEX ROWID    | T_CONTRACT_MASTER              |     1 |    46 |     2  (50)|
    |* 27 |            INDEX UNIQUE SCAN             | PK_T_CONTRACT_MASTER           |     1 |       |     1   (0)|
    |  28 |          TABLE ACCESS BY INDEX ROWID     | T_CHANNEL_TYPE                 |     1 |    12 |     2  (50)|
    |* 29 |           INDEX UNIQUE SCAN              | PK_T_CHANNEL_TYPE              |     1 |       |            |
    |  30 |         TABLE ACCESS BY INDEX ROWID      | T_COMPANY_ORGAN                |     1 |    36 |     2  (50)|
    |* 31 |          INDEX UNIQUE SCAN               | PK_T_COMPANY_ORGAN             |     1 |       |            |
    |  32 |        TABLE ACCESS BY INDEX ROWID       | T_CAPITAL_DISTRI_TYPE          |     1 |    25 |     2  (50)|
    |* 33 |         INDEX UNIQUE SCAN                | PK_T_CAPITAL_DISTRI_TYPE       |     1 |       |            |
    |  34 |       TABLE ACCESS BY INDEX ROWID        | T_CONTRACT_PRODUCT             |     1 |    10 |     2  (50)|
    |* 35 |        INDEX UNIQUE SCAN                 | PK_T_CONTRACT_PRODUCT          |     1 |       |     1   (0)|
    |  36 |      TABLE ACCESS BY INDEX ROWID         | T_PRODUCT_LIFE                 |     1 |    14 |     2  (50)|
    |* 37 |       INDEX UNIQUE SCAN                  | PK_T_PRODUCT_LIFE              |     1 |       |            |
    |* 38 |     INDEX RANGE SCAN                     | IDX_BIZ_ACCOUNTING_INFO__FEE_  |     1 |       |     2   (0)|
    ----------------------------------------------------------------------------------------------------------------
    10 - access("I"."SEGMENT1"="O"."ORGAN_ID")
      14 - access("I"."TRANSACTION_DATE">=TO_DATE('2011-11-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss') AND
                  "I"."POSTING_ID"=493997 AND "I"."TRANSACTION_DATE"<TO_DATE('2011-12-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss'))
           filter("I"."POSTING_ID"=493997)
      15 - access("A"."CRED_ID"=493997 AND "A"."ORGAN_ID"="I"."SEGMENT1" AND "A"."DISTRI_TYPE"="I"."REFERENCE3")
           filter(NVL("A"."POSTED",'N')='Y' AND "A"."DISTRI_TYPE"="I"."REFERENCE3")
      17 - filter(TO_DATE('2011-11-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss')<TO_DATE('2011-12-01 00:00:00',
                  'yyyy-mm-dd hh24:mi:ss') AND TO_DATE('2011-12-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss')>TO_DATE('2011-11-01
                  00:00:00', 'yyyy-mm-dd hh24:mi:ss'))
      18 - filter("T_COMPANY_ORGAN"."ORGAN_ID"='101')
      20 - access("T_COMPANY_ORGAN"."ORGAN_ID"='101')
      25 - access("T_COMPANY_ORGAN"."PARENT_ID"=NULL)
      27 - access("A"."POLICY_ID"="B"."POLICY_ID")
      29 - access("B"."POLICY_TYPE"="J"."INDIVIDUAL_GROUP")
      31 - access("B"."ORGAN_ID"="C"."ORGAN_ID")
      33 - access("A"."DISTRI_TYPE"="D"."DISTRI_TYPE")
      35 - access("A"."ITEM_ID"="F"."ITEM_ID")
      37 - access("A"."PRODUCT_ID"="E"."PRODUCT_ID")
      38 - access("A"."CAPITAL_ID"="T_BIZ_ACCOUNTING_INFO"."FEE_ID" AND "T_BIZ_ACCOUNTING_INFO"."DATA_TABLE"=7)
    


    所以系统设计的时候,应该尽量避免出现 left outer join, right outer join ,尤其是大表,大表更应该尽量避它作为外连接的驱动表

  • 相关阅读:
    强大的mono.cecil
    关于svn不能cleanup的问题
    SVN项目,快速查看项目的当前版本号
    jQuery选择器总结
    将Excel数据导入mysql数据库的几种方法
    SpringMVC表单标签简介
    mybatis动态SQL语句
    mysql时间格式化,按时间段查询MYSQL语句
    深入了解ios系统机制
    Eclipse 官方简体中文语言包下载地址及安装方法
  • 原文地址:https://www.cnblogs.com/hehe520/p/6330554.html
Copyright © 2020-2023  润新知