zoukankan      html  css  js  c++  java
  • 帮盖尔优化SQL子查询优化的经典案例

     上周五要下班的时候,盖尔发来一个SQL

    select tpc.policy_id,
           tcm.policy_code,
           tpf.organ_id,
           to_char(tpf.insert_time, 'YYYY-MM-DD') As insert_time,
           tpc.change_id,
           d.policy_code,
           e.company_name,
           f.real_name,
           tpf.fee_type,
           sum(tpf.pay_balance) as pay_balance,
           c.actual_type,
           tpc.notice_code,
           d.policy_type,
           g.mode_name as pay_mode
      from t_policy_change    tpc,
           t_contract_master  tcm,
           t_policy_fee       tpf,
           t_fee_type         c,
           t_contract_master  d,
           t_company_customer e,
           t_customer         f,
           t_pay_mode         g
     where tpc.change_id = tpf.change_id
       and tpf.policy_id = d.policy_id
       and tcm.policy_id = tpc.policy_id
       and tpf.receiv_status = 1 
       and tpf.fee_status = 1
       and tpf.payment_id is null
       and tpf.fee_type = c.type_id
       and tpf.pay_mode = g.mode_id
       and d.company_id = e.company_id(+)
       and d.applicant_id = f.customer_id(+)
       and tpf.organ_id in
           (select 
             organ_id
              from t_company_organ
             start with organ_id = '101'
            connect by prior organ_id = parent_id)
     group by tpc.policy_id,
              tpc.change_id,
              tpf.fee_type,
              to_char(tpf.insert_time, 'YYYY-MM-DD'),
              c.actual_type,
              d.policy_code,
              g.mode_name,
              e.company_name,
              f.real_name,
              tpc.notice_code,
              d.policy_type,
              tpf.organ_id,
              tcm.policy_code
     order by change_id, fee_type
    
    SQL> select * from table(dbms_xplan.display);
    
    PLAN_TABLE_OUTPUT
    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    | Id  | Operation                           |  Name                       | Rows  | Bytes |TempSpc| Cost (%CPU)|
    ----------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                    |                             | 45962 |    11M|       | 45650   (0)|
    |   1 |  SORT GROUP BY                      |                             | 45962 |    11M|    23M| 45650   (0)|
    |*  2 |   HASH JOIN                         |                             | 45962 |    11M|       | 43908   (0)|
    |   3 |    INDEX FULL SCAN                  | T_FEE_TYPE_IDX_003          |   106 |   636 |       |     1   (0)|
    |   4 |    NESTED LOOPS OUTER               |                             | 45962 |    11M|       | 43906   (0)|
    |*  5 |     HASH JOIN                       |                             | 45962 |  7271K|  6824K| 43905   (0)|
    |   6 |      NESTED LOOPS                   |                             | 45961 |  6283K|       | 42312   (0)|
    |*  7 |       HASH JOIN SEMI                |                             | 45961 |  5655K|    50M| 33120   (1)|
    |*  8 |        HASH JOIN OUTER              |                             |   400K|    45M|    44M| 32315   (1)|
    |*  9 |         HASH JOIN                   |                             |   400K|    39M|    27M| 26943   (0)|
    |* 10 |          HASH JOIN                  |                             |   400K|    23M|       | 16111   (0)|
    |  11 |           TABLE ACCESS FULL         | T_PAY_MODE                  |    25 |   525 |       |     2   (0)|
    |* 12 |           TABLE ACCESS FULL         | T_POLICY_FEE                |   400K|    15M|       | 16107   (0)|
    |  13 |          TABLE ACCESS FULL          | T_CONTRACT_MASTER           |  1136K|    46M|       |  9437   (0)|
    |  14 |         VIEW                        | index_join_007            |  2028K|    30M|       |            |
    |* 15 |          HASH JOIN                  |                             |   400K|    45M|    44M| 32315   (1)|
    |  16 |           INDEX FAST FULL SCAN      | PK_T_CUSTOMER               |  2028K|    30M|       |   548   (0)|
    |  17 |           INDEX FAST FULL SCAN      | IDX_CUSTOMER__BIR_REAL_GEN  |  2028K|    30M|       |   548   (0)|
    |  18 |        VIEW                         | VW_NSO_1                    |     7 |    42 |       |            |
    |* 19 |         CONNECT BY WITH FILTERING   |                             |       |       |       |            |
    |  20 |          NESTED LOOPS               |                             |       |       |       |            |
    |* 21 |           INDEX UNIQUE SCAN         | PK_T_COMPANY_ORGAN          |     1 |     6 |       |            |
    |  22 |           TABLE ACCESS BY USER ROWID| T_COMPANY_ORGAN             |       |       |       |            |
    |  23 |          NESTED LOOPS               |                             |       |       |       |            |
    |  24 |           BUFFER SORT               |                             |     7 |    70 |       |            |
    |  25 |            CONNECT BY PUMP          |                             |       |       |       |            |
    |* 26 |           INDEX RANGE SCAN          | T_COMPANY_ORGAN_IDX_002     |     7 |    70 |       |     1   (0)|
    |  27 |       TABLE ACCESS BY INDEX ROWID   | T_POLICY_CHANGE             |     1 |    14 |       |     2  (50)|
    |* 28 |        INDEX UNIQUE SCAN            | PK_T_POLICY_CHANGE          |     1 |       |       |     1   (0)|
    |  29 |      INDEX FAST FULL SCAN           | IDX1_ACCEPT_DATE            |  1136K|    23M|       |   899   (0)|
    |  30 |     TABLE ACCESS BY INDEX ROWID     | T_COMPANY_CUSTOMER          |     1 |    90 |       |     2  (50)|
    |* 31 |      INDEX UNIQUE SCAN              | PK_T_COMPANY_CUSTOMER       |     1 |       |       |            |
    ----------------------------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - access("TPF"."FEE_TYPE"="C"."TYPE_ID")
       5 - access("TCM"."POLICY_ID"="TPC"."POLICY_ID")
       7 - access("TPF"."ORGAN_ID"="VW_NSO_1"."$nso_col_1")
       8 - access("D"."APPLICANT_ID"="F"."CUSTOMER_ID"(+))
       9 - access("TPF"."POLICY_ID"="D"."POLICY_ID")
      10 - access("TPF"."PAY_MODE"="G"."MODE_ID")
      12 - filter("TPF"."CHANGE_ID" IS NOT NULL AND TO_NUMBER("TPF"."RECEIV_STATUS")=1 AND "TPF"."FEE_STATUS"=1 AND
                  "TPF"."PAYMENT_ID" IS NULL)
      15 - access("indexjoin_alias_012".ROWID="indexjoin_alias_011".ROWID)
      19 - filter("T_COMPANY_ORGAN"."ORGAN_ID"='101')
      21 - access("T_COMPANY_ORGAN"."ORGAN_ID"='101')
      26 - access("T_COMPANY_ORGAN"."PARENT_ID"=NULL)
      28 - access("TPC"."CHANGE_ID"="TPF"."CHANGE_ID")
      31 - access("D"."COMPANY_ID"="E"."COMPANY_ID"(+))
    
    55 rows selected
    
    Statistics
    ----------------------------------------------------------
             21  recursive calls
              0  db block gets
         125082  consistent gets
          21149  physical reads
              0  redo size
           2448  bytes sent via SQL*Net to client
            656  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              4  sorts (memory)
              0  sorts (disk)
             11  rows processed


     


    这个SQL要21秒才能跑完,逻辑读12W左右,问我能不能优化。优化这个SQL我只花了1分钟左右的时间,因为太简单了
    你们看这个SQL是典型的JOIN,对付这种SQL肯定要让表走索引,但是从执行计划上看有个1千万行的表T_CONTRACT_MASTER走的是全表扫描,
    T_POLICY_FEE 这个400W行的表也是走全表扫描,那么它不慢才怪呢,然后SQL的过滤条件有个 in 子查询
           (select
             organ_id
              from t_company_organ
             start with organ_id = '101'
            connect by prior organ_id = parent_id)
    从执行计划上看,CBO对这儿子查询进行了unnest,因为通常情况下CBO认为子查询被unnest之后性能好于filter       

    于是我让盖尔查询 子查询返回多少行        
    select  organ_id
              from t_company_organ
             start with organ_id = '101'
            connect by prior organ_id = parent_id   ---盖尔说它返回1行        

    对于子查询,如果它返回数据很少(这里返回1行),那么可以让它走filter, 而且filter基本上是在SQL最后去阶段执行,这样t_policy_fee就可以走索引了
    所以我给这个子查询加了个HINT,禁止子查询扩展

    select tpc.policy_id,
           tcm.policy_code,
           tpf.organ_id,
           to_char(tpf.insert_time, 'YYYY-MM-DD') As insert_time,
           tpc.change_id,
           d.policy_code,
           e.company_name,
           f.real_name,
           tpf.fee_type,
           sum(tpf.pay_balance) as pay_balance,
           c.actual_type,
           tpc.notice_code,
           d.policy_type,
           g.mode_name as pay_mode
      from t_policy_change    tpc,
           t_contract_master  tcm,
           t_policy_fee       tpf,
           t_fee_type         c,
           t_contract_master  d,
           t_company_customer e,
           t_customer         f,
           t_pay_mode         g
     where tpc.change_id = tpf.change_id
       and tpf.policy_id = d.policy_id
       and tcm.policy_id = tpc.policy_id
       and tpf.receiv_status = '1'  ---这里原来没引号,是开发那SB搞忘了写'',我让盖尔添加上了,不添加上就没法用索引
       and tpf.fee_status = 1
       and tpf.payment_id is null
       and tpf.fee_type = c.type_id
       and tpf.pay_mode = g.mode_id
       and d.company_id = e.company_id(+)
       and d.applicant_id = f.customer_id(+)
       and tpf.organ_id in
           (select /*+ no_unnest */     --此处的HINT后加的
             organ_id
              from t_company_organ
             start with organ_id = '101'
            connect by prior organ_id = parent_id)
     group by tpc.policy_id,
              tpc.change_id,
              tpf.fee_type,
              to_char(tpf.insert_time, 'YYYY-MM-DD'),
              c.actual_type,
              d.policy_code,
              g.mode_name,
              e.company_name,
              f.real_name,
              tpc.notice_code,
              d.policy_type,
              tpf.organ_id,
              tcm.policy_code
     order by change_id, fee_type
    
    SQL> select * from table(dbms_xplan.display);
    
    PLAN_TABLE_OUTPUT
    --------------------------------------------------------------------------------------------------------------------
    | Id  | Operation                            |  Name                          | Rows  | Bytes |TempSpc| Cost (%CPU)|
    --------------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                     |                                | 20026 |  4928K|       | 68615  (30)|
    |   1 |  SORT GROUP BY                       |                                | 20026 |  4928K|    10M| 28563   (0)|
    |*  2 |   FILTER                             |                                |       |       |       |            |
    |   3 |    NESTED LOOPS                      |                                | 20026 |  4928K|       | 27812   (0)|
    |   4 |     NESTED LOOPS                     |                                | 20026 |  4498K|       | 23807   (0)|
    |   5 |      NESTED LOOPS OUTER              |                                | 20026 |  4224K|       | 19802   (0)|
    |   6 |       NESTED LOOPS OUTER             |                                | 20026 |  3911K|       | 15797   (0)|
    |   7 |        NESTED LOOPS                  |                                | 20026 |  2151K|       | 15796   (0)|
    |*  8 |         HASH JOIN                    |                                | 20026 |  1310K|       | 11791   (0)|
    |   9 |          INDEX FULL SCAN             | T_FEE_TYPE_IDX_003             |   106 |   636 |       |     1   (0)|
    |* 10 |          HASH JOIN                   |                                | 20026 |  1192K|       | 11789   (0)|
    |  11 |           TABLE ACCESS FULL          | T_PAY_MODE                     |    25 |   525 |       |     2   (0)|
    |* 12 |           TABLE ACCESS BY INDEX ROWID| T_POLICY_FEE                   | 20026 |   782K|       | 11786   (0)|
    |* 13 |            INDEX RANGE SCAN          | IDX_POLICY_FEE__RECEIV_STATUS  |  1243K|       |       | 10188   (0)|
    |  14 |         TABLE ACCESS BY INDEX ROWID  | T_CONTRACT_MASTER              |     1 |    43 |       |     2  (50)|
    |* 15 |          INDEX UNIQUE SCAN           | PK_T_CONTRACT_MASTER           |     1 |       |       |     1   (0)|
    |  16 |        TABLE ACCESS BY INDEX ROWID   | T_COMPANY_CUSTOMER             |     1 |    90 |       |     2  (50)|
    |* 17 |         INDEX UNIQUE SCAN            | PK_T_COMPANY_CUSTOMER          |     1 |       |       |            |
    |  18 |       TABLE ACCESS BY INDEX ROWID    | T_CUSTOMER                     |     1 |    16 |       |     2  (50)|
    |* 19 |        INDEX UNIQUE SCAN             | PK_T_CUSTOMER                  |     1 |       |       |     1   (0)|
    |  20 |      TABLE ACCESS BY INDEX ROWID     | T_POLICY_CHANGE                |     1 |    14 |       |     2  (50)|
    |* 21 |       INDEX UNIQUE SCAN              | PK_T_POLICY_CHANGE             |     1 |       |       |     1   (0)|
    |  22 |     TABLE ACCESS BY INDEX ROWID      | T_CONTRACT_MASTER              |     1 |    22 |       |     2  (50)|
    |* 23 |      INDEX UNIQUE SCAN               | PK_T_CONTRACT_MASTER           |     1 |       |       |     1   (0)|
    |* 24 |    FILTER                            |                                |       |       |       |            |
    |* 25 |     CONNECT BY WITH FILTERING        |                                |       |       |       |            |
    |  26 |      NESTED LOOPS                    |                                |       |       |       |            |
    |* 27 |       INDEX UNIQUE SCAN              | PK_T_COMPANY_ORGAN             |     1 |     6 |       |            |
    |  28 |       TABLE ACCESS BY USER ROWID     | T_COMPANY_ORGAN                |       |       |       |            |
    |  29 |      NESTED LOOPS                    |                                |       |       |       |            |
    |  30 |       BUFFER SORT                    |                                |     7 |    70 |       |            |
    |  31 |        CONNECT BY PUMP               |                                |       |       |       |            |
    |* 32 |       INDEX RANGE SCAN               | T_COMPANY_ORGAN_IDX_002        |     7 |    70 |       |     1   (0)|
    --------------------------------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - filter( EXISTS (SELECT /*+ NO_UNNEST */ 0 FROM "T_COMPANY_ORGAN" "T_COMPANY_ORGAN" WHERE
                  "T_COMPANY_ORGAN"."PARENT_ID"=NULL AND ("T_COMPANY_ORGAN"."ORGAN_ID"=:B1)))
       8 - access("SYS_ALIAS_1"."FEE_TYPE"="C"."TYPE_ID")
      10 - access("SYS_ALIAS_1"."PAY_MODE"="G"."MODE_ID")
      12 - filter("SYS_ALIAS_1"."CHANGE_ID" IS NOT NULL AND "SYS_ALIAS_1"."FEE_STATUS"=1 AND "SYS_ALIAS_1"."PAYMENT_ID"
                  IS NULL)
      13 - access("SYS_ALIAS_1"."RECEIV_STATUS"='1')
      15 - access("SYS_ALIAS_1"."POLICY_ID"="D"."POLICY_ID")
      17 - access("D"."COMPANY_ID"="E"."COMPANY_ID"(+))
      19 - access("D"."APPLICANT_ID"="F"."CUSTOMER_ID"(+))
      21 - access("TPC"."CHANGE_ID"="SYS_ALIAS_1"."CHANGE_ID")
      23 - access("TCM"."POLICY_ID"="TPC"."POLICY_ID")
      24 - filter("T_COMPANY_ORGAN"."ORGAN_ID"=:B1)
      25 - filter("T_COMPANY_ORGAN"."ORGAN_ID"='101')
      27 - access("T_COMPANY_ORGAN"."ORGAN_ID"='101')
      32 - access("T_COMPANY_ORGAN"."PARENT_ID"=NULL)
    
    58 rows selected.
    
    Statistics
    ----------------------------------------------------------
              0  recursive calls
              0  db block gets
           2817  consistent gets
              0  physical reads
              0  redo size
           2268  bytes sent via SQL*Net to client
            656  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
             40  sorts (memory)
              0  sorts (disk)
              9  rows processed
    


    最终这个SQL能在1秒以内跑完,逻辑读下降到2817 ,到此我就没继续优化了,这个时候停止优化吧,别的了强迫优化症
    这个优化案例很简单,我都不好意思贴在博客上,通过这个文章你要学到的就是,如果子查询返回数据很少,那么不妨让它走filter        

  • 相关阅读:
    atitit.ntfs ext 文件系统新特性对比
    Atitit.图片木马的原理与防范 attilax 总结
    Atitit.图片木马的原理与防范 attilax 总结
    Atitit.jdk java8的语法特性详解 attilax 总结
    Atitit.jdk java8的语法特性详解 attilax 总结
    Atitit.远程接口 监控与木马   常用的api 标准化v2 q216
    Atitit.远程接口 监控与木马   常用的api 标准化v2 q216
    Atitit..jdk java 各版本新特性 1.0 1.1 1.2 1.3 1.4 1.5(5.0) 1.6(6.0) 7.0 8.0 9.0 attilax 大总结
    Atitit..jdk java 各版本新特性 1.0 1.1 1.2 1.3 1.4 1.5(5.0) 1.6(6.0) 7.0 8.0 9.0 attilax 大总结
    Atitit.跨平台预定义函数 魔术方法 魔术函数 钩子函数 api兼容性草案 v2 q216  java c# php js.docx
  • 原文地址:https://www.cnblogs.com/hehe520/p/6330557.html
Copyright © 2011-2022 走看看