zoukankan      html  css  js  c++  java
  • 子查询里面有树形查询,子查询选择使用in/exists需要特别留意

    今天下午盖尔又发来一条坑爹的SQL,哎,最近被盖尔给咕噜惨了,老是发一些鸟SQL让我调,最近都帮忙调了N多个SQL了,还好盖尔良心发现了,说这个月末给我重200元的话费大笑。认识盖尔的人都知道,盖尔发的SQL那绝对是坑爹的,说它是OLTP的SQL不像,因为OLTP的SQL没那么复杂,说它是OLAP的也不像,因为我没看见典型的事实表,维度表的JOIN,那么唯一的解释就是他们DB设计的人是SB。

     盖尔的SQL和执行计划如下:

    select distinct decode(length(a.category_id),
                           5,
                           decode(a.origin_type, 801, 888888, 999999),
                           a.category_id) category_id,
                    a.notice_code,
                    a.treat_status,
                    lr.real_name as receiver_name,
                    f.send_code,
                    f.policy_code,
                    g.real_name agent_name,
                    f.organ_id,
                    f.dept_id,
                    a.policy_id,
                    a.change_id,
                    a.case_id,
                    a.group_policy_id,
                    a.fee_id,
                    a.auth_id,
                    a.pay_id,
                    cancel_appoint.appoint_time cancel_appoint_time,
                    a.insert_time,
                    a.send_time,
                    a.end_time,
                    f.agency_code,
                    a.REPLY_TIME,
                    a.REPLY_EMP_ID,
                    a.FIRST_DUTY,
                    a.NEED_SEND_PRINT,
                    11 source
      from t_policy_problem        a,
           t_policy                f,
           t_agent                 g,
           t_letter_receiver       lr,
           t_problem_category      pc,
           t_policy_cancel_appoint cancel_appoint
     where f.agent_id = g.agent_id(+)
       and a.policy_id = f.policy_id(+)
       and lr.main_receiver = 'Y'
       and a.category_id = pc.category_id
       and a.item_id = lr.item_id
       and a.policy_id = cancel_appoint.policy_id(+)
       And a.Item_Id = (Select Max(item_id)
                          From t_Policy_Problem
                         Where notice_code = a.notice_code)
       and a.policy_id is not null
       and a.notice_code is not null
       and a.change_id is null
       and a.case_id is null
       and a.group_policy_id is null
       and a.origin_type not in (801, 802)
       and a.pay_id is null
       and a.category_id not in (130103, 130104, 130102, 140102, 140101)
       and f.policy_type = '1'
       and (a.fee_id is null or (a.fee_id is not null and a.origin_type = 701))
       and exists((select  1
                    from t_dept
                   where f.dept_id = dept_id
                   start with dept_id = '1020200028'
                  connect by parent_id = prior dept_id))
       and exists (select 1
              from T_COMPANY_ORGAN
             where f.organ_id = organ_id
             start with organ_id = '10202'
            connect by parent_id = prior organ_id)
       and pc.NEED_PRITN = 'Y';
       
    
    SQL> select * from table(dbms_xplan.display);
    
    PLAN_TABLE_OUTPUT
    -------------------------------------------------------------------------------------------------------
    | Id  | Operation                          |  Name                       | Rows  | Bytes | Cost (%CPU)|
    -------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                   |                             |     1 |   236 |   741   (1)|
    |   1 |  SORT UNIQUE                       |                             |     1 |   236 |   681   (0)|
    |*  2 |   FILTER                           |                             |       |       |            |
    |   3 |    NESTED LOOPS                    |                             |     1 |   236 |   666   (1)|
    |   4 |     NESTED LOOPS OUTER             |                             |     1 |   219 |   665   (1)|
    |   5 |      NESTED LOOPS                  |                             |     1 |   203 |   664   (1)|
    |   6 |       NESTED LOOPS OUTER           |                             |     1 |   196 |   663   (1)|
    |   7 |        NESTED LOOPS                |                             |     1 |   182 |   662   (1)|
    |*  8 |         TABLE ACCESS FULL          | T_POLICY_PROBLEM            |     1 |   107 |   660   (0)|
    |*  9 |         TABLE ACCESS BY INDEX ROWID| T_POLICY                    |     1 |    75 |     2  (50)|
    |* 10 |          INDEX UNIQUE SCAN         | PK_T_POLICY                 |     1 |       |     1   (0)|
    |  11 |        TABLE ACCESS BY INDEX ROWID | T_POLICY_CANCEL_APPOINT     |     1 |    14 |     2  (50)|
    |* 12 |         INDEX UNIQUE SCAN          | UK1_POLICY_CANCEL_APPOINT   |     1 |       |            |
    |* 13 |       TABLE ACCESS BY INDEX ROWID  | T_PROBLEM_CATEGORY          |     1 |     7 |     2  (50)|
    |* 14 |        INDEX UNIQUE SCAN           | PK_T_PROBLEM_CATEGORY       |     1 |       |            |
    |  15 |      TABLE ACCESS BY INDEX ROWID   | T_AGENT                     |     1 |    16 |     2  (50)|
    |* 16 |       INDEX UNIQUE SCAN            | PK_T_AGENT                  |     1 |       |            |
    |* 17 |     INDEX RANGE SCAN               | T_LETTER_RECEIVER_IDX_001   |     1 |    17 |     2   (0)|
    |  18 |    SORT AGGREGATE                  |                             |     1 |    21 |            |
    |  19 |     TABLE ACCESS BY INDEX ROWID    | T_POLICY_PROBLEM            |     1 |    21 |     2  (50)|
    |* 20 |      INDEX RANGE SCAN              | IDX_POLICY_PROBLEM__N_CODE  |     1 |       |     3   (0)|
    |* 21 |    FILTER                          |                             |       |       |            |
    |* 22 |     CONNECT BY WITH FILTERING      |                             |       |       |            |
    |  23 |      NESTED LOOPS                  |                             |       |       |            |
    |* 24 |       INDEX UNIQUE SCAN            | PK_T_DEPT                   |     1 |    17 |     1   (0)|
    |  25 |       TABLE ACCESS BY USER ROWID   | T_DEPT                      |       |       |            |
    |  26 |      HASH JOIN                     |                             |       |       |            |
    |  27 |       CONNECT BY PUMP              |                             |       |       |            |
    |  28 |       TABLE ACCESS FULL            | T_DEPT                      | 30601 |   896K|    56   (0)|
    |* 29 |    FILTER                          |                             |       |       |            |
    |* 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 - filter("SYS_ALIAS_1"."ITEM_ID"= (SELECT /*+ */ MAX("T_POLICY_PROBLEM"."ITEM_ID") FROM
                  "T_POLICY_PROBLEM" "T_POLICY_PROBLEM" WHERE "T_POLICY_PROBLEM"."NOTICE_CODE"=:B1) AND  EXISTS (SELECT
                  /*+ */ 0 FROM "T_DEPT" "T_DEPT" AND ("T_DEPT"."DEPT_ID"=:B2)) AND  EXISTS (SELECT /*+ */ 0 FROM
                  "T_COMPANY_ORGAN" "T_COMPANY_ORGAN" WHERE "T_COMPANY_ORGAN"."PARENT_ID"=NULL AND
                  ("T_COMPANY_ORGAN"."ORGAN_ID"=:B3)))
       8 - filter("SYS_ALIAS_1"."POLICY_ID" IS NOT NULL AND "SYS_ALIAS_1"."NOTICE_CODE" IS NOT NULL AND
                  "SYS_ALIAS_1"."CHANGE_ID" IS NULL AND "SYS_ALIAS_1"."CASE_ID" IS NULL AND
                  "SYS_ALIAS_1"."GROUP_POLICY_ID" IS NULL AND TO_NUMBER("SYS_ALIAS_1"."ORIGIN_TYPE")<>801 AND
                  TO_NUMBER("SYS_ALIAS_1"."ORIGIN_TYPE")<>802 AND "SYS_ALIAS_1"."PAY_ID" IS NULL AND
                  "SYS_ALIAS_1"."CATEGORY_ID"<>130103 AND "SYS_ALIAS_1"."CATEGORY_ID"<>130104 AND
                  "SYS_ALIAS_1"."CATEGORY_ID"<>130102 AND "SYS_ALIAS_1"."CATEGORY_ID"<>140102 AND
                  "SYS_ALIAS_1"."CATEGORY_ID"<>140101 AND ("SYS_ALIAS_1"."FEE_ID" IS NULL OR "SYS_ALIAS_1"."FEE_ID" IS
                  NOT NULL AND TO_NUMBER("SYS_ALIAS_1"."ORIGIN_TYPE")=701))
       9 - filter(TO_NUMBER("SYS_ALIAS_3"."POLICY_TYPE")=1)
      10 - access("SYS_ALIAS_1"."POLICY_ID"="SYS_ALIAS_3"."POLICY_ID")
      12 - access("SYS_ALIAS_1"."POLICY_ID"="CANCEL_APPOINT"."POLICY_ID"(+))
      13 - filter("PC"."NEED_PRITN"='Y')
      14 - access("SYS_ALIAS_1"."CATEGORY_ID"="PC"."CATEGORY_ID")
           filter("PC"."CATEGORY_ID"<>130103 AND "PC"."CATEGORY_ID"<>130104 AND "PC"."CATEGORY_ID"<>130102
                  AND "PC"."CATEGORY_ID"<>140102 AND "PC"."CATEGORY_ID"<>140101)
      16 - access("SYS_ALIAS_3"."AGENT_ID"="G"."AGENT_ID"(+))
      17 - access("LR"."MAIN_RECEIVER"='Y' AND "SYS_ALIAS_1"."ITEM_ID"="LR"."ITEM_ID")
      20 - access("T_POLICY_PROBLEM"."NOTICE_CODE"=:B1)
      21 - filter("T_DEPT"."DEPT_ID"=:B1)
      22 - filter("T_DEPT"."DEPT_ID"='1020200028')
      24 - access("T_DEPT"."DEPT_ID"='1020200028')
      29 - filter("T_COMPANY_ORGAN"."ORGAN_ID"=:B1)
      30 - filter("T_COMPANY_ORGAN"."ORGAN_ID"='10202')
      32 - access("T_COMPANY_ORGAN"."ORGAN_ID"='10202')
      37 - access("T_COMPANY_ORGAN"."PARENT_ID"=NULL)
    
    77 rows selected.

    这个SQL里面又有 (TO_NUMBER("SYS_ALIAS_3"."POLICY_TYPE")=1) ,写SQL的那人啊 为啥又不加上'' 他们的开发人员水平真的是太那个啥了

    盖尔说这个SQL跑不出结果,让他查询等待事件,是 db file sequential read 

    这个SQL之所以跑不出结果是因为子查询里面有 start with.... connect by ,

    子查询外面使用的是exists,CBO里面有个限制:当子查询里面有 start with....connect by , CBO不会对子查询进行转换,所以这个时候就只能走filter了

    但是子查询又要返回很多结果 所以帮盖尔改写了SQL,用in 代替 exists

    select distinct decode(length(a.category_id),
                           5,
                           decode(a.origin_type, 801, 888888, 999999),
                           a.category_id) category_id,
                    a.notice_code,
                    a.treat_status,
                    lr.real_name as receiver_name,
                    f.send_code,
                    f.policy_code,
                    g.real_name agent_name,
                    f.organ_id,
                    f.dept_id,
                    a.policy_id,
                    a.change_id,
                    a.case_id,
                    a.group_policy_id,
                    a.fee_id,
                    a.auth_id,
                    a.pay_id,
                    cancel_appoint.appoint_time cancel_appoint_time,
                    a.insert_time,
                    a.send_time,
                    a.end_time,
                    f.agency_code,
                    a.REPLY_TIME,
                    a.REPLY_EMP_ID,
                    a.FIRST_DUTY,
                    a.NEED_SEND_PRINT,
                    11 source
      from t_policy_problem        a,
           t_policy                f,
           t_agent                 g,
           t_letter_receiver       lr,
           t_problem_category      pc,
           t_policy_cancel_appoint cancel_appoint
     where f.agent_id = g.agent_id(+)
       and a.policy_id = f.policy_id(+)
       and lr.main_receiver = 'Y'
       and a.category_id = pc.category_id
       and a.item_id = lr.item_id
       and a.policy_id = cancel_appoint.policy_id(+)
       And a.Item_Id = (Select Max(item_id)
                          From t_Policy_Problem
                         Where notice_code = a.notice_code)
       and a.policy_id is not null
       and a.notice_code is not null
       and a.change_id is null
       and a.case_id is null
       and a.group_policy_id is null
       and a.origin_type not in (801, 802)
       and a.pay_id is null
       and a.category_id not in (130103, 130104, 130102, 140102, 140101)
       and f.policy_type = '1'
       and (a.fee_id is null or (a.fee_id is not null and a.origin_type = 701))
       and f.dept_id in (select dept_id
                    from t_dept
                   start with dept_id = '1020200028'
                  connect by parent_id = prior dept_id))
       and f.organ_id in (select organ_id
              from T_COMPANY_ORGAN
             start with organ_id = '10202'
            connect by parent_id = prior organ_id)
       and pc.NEED_PRITN = 'Y';
       
    ----------------------------------------------------------------------------------------------------------
    | Id  | Operation                             |  Name                       | Rows  | Bytes | Cost (%CPU)|
    ----------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                      |                             |     1 |   259 |   742   (1)|
    |   1 |  SORT UNIQUE                          |                             |     1 |   259 |   740   (0)|
    |*  2 |   FILTER                              |                             |       |       |            |
    |*  3 |    HASH JOIN                          |                             |     1 |   259 |   725   (1)|
    |   4 |     NESTED LOOPS                      |                             |     1 |   253 |   723   (1)|
    |   5 |      NESTED LOOPS                     |                             |     1 |   236 |   722   (1)|
    |   6 |       NESTED LOOPS OUTER              |                             |     1 |   229 |   721   (1)|
    |   7 |        NESTED LOOPS OUTER             |                             |     1 |   215 |   720   (1)|
    |*  8 |         HASH JOIN                     |                             |     1 |   199 |   719   (1)|
    |   9 |          NESTED LOOPS                 |                             |     1 |   182 |   662   (1)|
    |* 10 |           TABLE ACCESS FULL           | T_POLICY_PROBLEM            |     1 |   107 |   660   (0)|
    |* 11 |           TABLE ACCESS BY INDEX ROWID | T_POLICY                    |     1 |    75 |     2  (50)|
    |* 12 |            INDEX UNIQUE SCAN          | PK_T_POLICY                 |     1 |       |     1   (0)|
    |  13 |          VIEW                         | VW_NSO_1                    | 30601 |   508K|            |
    |* 14 |           CONNECT BY WITH FILTERING   |                             |       |       |            |
    |  15 |            NESTED LOOPS               |                             |       |       |            |
    |* 16 |             INDEX UNIQUE SCAN         | PK_T_DEPT                   |     1 |    17 |     1   (0)|
    |  17 |             TABLE ACCESS BY USER ROWID| T_DEPT                      |       |       |            |
    |  18 |            HASH JOIN                  |                             |       |       |            |
    |  19 |             CONNECT BY PUMP           |                             |       |       |            |
    |  20 |             TABLE ACCESS FULL         | T_DEPT                      | 30601 |   896K|    56   (0)|
    |  21 |         TABLE ACCESS BY INDEX ROWID   | T_AGENT                     |     1 |    16 |     2  (50)|
    |* 22 |          INDEX UNIQUE SCAN            | PK_T_AGENT                  |     1 |       |            |
    |  23 |        TABLE ACCESS BY INDEX ROWID    | T_POLICY_CANCEL_APPOINT     |     1 |    14 |     2  (50)|
    |* 24 |         INDEX UNIQUE SCAN             | UK1_POLICY_CANCEL_APPOINT   |     1 |       |            |
    |* 25 |       TABLE ACCESS BY INDEX ROWID     | T_PROBLEM_CATEGORY          |     1 |     7 |     2  (50)|
    |* 26 |        INDEX UNIQUE SCAN              | PK_T_PROBLEM_CATEGORY       |     1 |       |            |
    |* 27 |      INDEX RANGE SCAN                 | T_LETTER_RECEIVER_IDX_001   |     1 |    17 |     2   (0)|
    |  28 |     VIEW                              | VW_NSO_2                    |     7 |    42 |            |
    |* 29 |      CONNECT BY WITH FILTERING        |                             |       |       |            |
    |  30 |       NESTED LOOPS                    |                             |       |       |            |
    |* 31 |        INDEX UNIQUE SCAN              | PK_T_COMPANY_ORGAN          |     1 |     6 |            |
    |  32 |        TABLE ACCESS BY USER ROWID     | T_COMPANY_ORGAN             |       |       |            |
    |  33 |       NESTED LOOPS                    |                             |       |       |            |
    |  34 |        BUFFER SORT                    |                             |     7 |    70 |            |
    |  35 |         CONNECT BY PUMP               |                             |       |       |            |
    |* 36 |        INDEX RANGE SCAN               | T_COMPANY_ORGAN_IDX_002     |     7 |    70 |     1   (0)|
    |  37 |    SORT AGGREGATE                     |                             |     1 |    21 |            |
    |  38 |     TABLE ACCESS BY INDEX ROWID       | T_POLICY_PROBLEM            |     1 |    21 |     2  (50)|
    |* 39 |      INDEX RANGE SCAN                 | IDX_POLICY_PROBLEM__N_CODE  |     1 |       |     3   (0)|
    ----------------------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - filter("SYS_ALIAS_1"."ITEM_ID"= (SELECT /*+ */ MAX("T_POLICY_PROBLEM"."ITEM_ID") FROM
                  "T_POLICY_PROBLEM" "T_POLICY_PROBLEM" WHERE "T_POLICY_PROBLEM"."NOTICE_CODE"=:B1))
       3 - access("F"."ORGAN_ID"="VW_NSO_2"."$nso_col_1")
       8 - access("F"."DEPT_ID"="VW_NSO_1"."$nso_col_1")
      10 - filter("SYS_ALIAS_1"."POLICY_ID" IS NOT NULL AND "SYS_ALIAS_1"."NOTICE_CODE" IS NOT NULL AND
                  "SYS_ALIAS_1"."CHANGE_ID" IS NULL AND "SYS_ALIAS_1"."CASE_ID" IS NULL AND "SYS_ALIAS_1"."GROUP_POLICY_ID"
                  IS NULL AND TO_NUMBER("SYS_ALIAS_1"."ORIGIN_TYPE")<>801 AND TO_NUMBER("SYS_ALIAS_1"."ORIGIN_TYPE")<>802
                  AND "SYS_ALIAS_1"."PAY_ID" IS NULL AND "SYS_ALIAS_1"."CATEGORY_ID"<>130103 AND
                  "SYS_ALIAS_1"."CATEGORY_ID"<>130104 AND "SYS_ALIAS_1"."CATEGORY_ID"<>130102 AND
                  "SYS_ALIAS_1"."CATEGORY_ID"<>140102 AND "SYS_ALIAS_1"."CATEGORY_ID"<>140101 AND ("SYS_ALIAS_1"."FEE_ID"
                  IS NULL OR "SYS_ALIAS_1"."FEE_ID" IS NOT NULL AND TO_NUMBER("SYS_ALIAS_1"."ORIGIN_TYPE")=701))
      11 - filter("F"."POLICY_TYPE"='1')
      12 - access("SYS_ALIAS_1"."POLICY_ID"="F"."POLICY_ID")
      14 - filter("T_DEPT"."DEPT_ID"='1020200028')
      16 - access("T_DEPT"."DEPT_ID"='1020200028')
      22 - access("F"."AGENT_ID"="G"."AGENT_ID"(+))
      24 - access("SYS_ALIAS_1"."POLICY_ID"="CANCEL_APPOINT"."POLICY_ID"(+))
      25 - filter("PC"."NEED_PRITN"='Y')
      26 - access("SYS_ALIAS_1"."CATEGORY_ID"="PC"."CATEGORY_ID")
           filter("PC"."CATEGORY_ID"<>130103 AND "PC"."CATEGORY_ID"<>130104 AND "PC"."CATEGORY_ID"<>130102
                  AND "PC"."CATEGORY_ID"<>140102 AND "PC"."CATEGORY_ID"<>140101)
      27 - access("LR"."MAIN_RECEIVER"='Y' AND "SYS_ALIAS_1"."ITEM_ID"="LR"."ITEM_ID")
      29 - filter("T_COMPANY_ORGAN"."ORGAN_ID"='10202')
      31 - access("T_COMPANY_ORGAN"."ORGAN_ID"='10202')
      36 - access("T_COMPANY_ORGAN"."PARENT_ID"=NULL)
      39 - access("T_POLICY_PROBLEM"."NOTICE_CODE"=:B1)
    
    75 rows selected.


    SQL 改写之后,35秒就能出结果了,以前是不出结果啊!恩,这个SQL优化就到此为止吧。

    我还想提的就是,他的这个SQL里面的过滤条件,

       and a.policy_id is not null
       and a.notice_code is not null
       and a.change_id is null
       and a.case_id is null
       and a.group_policy_id is null
       and a.origin_type not in (801, 802)
       and a.pay_id is null
       and a.category_id not in (130103, 130104, 130102, 140102, 140101)

    is null, is not null , not in  ...... 这都是什么需求啊,这个系统设计人员确实“牛逼”

    这个案例恰好和 http://blog.csdn.net/robinson1988/article/details/7002545 这个案例完全相反,所以,当你遇到子查询里面有树形查询,子查询选择使用in/exists需要特别留意
  • 相关阅读:
    PAT 1012 数字分类 (20)
    HDU 3903 Trigonometric Function(数学定理)
    HUST 1600 Lucky Numbers
    HUST 1599
    FZU 2092 收集水晶(记忆化搜索)
    Java实现 蓝桥杯 算法训练 字符串长度(IO无敌)
    Java实现 蓝桥杯 算法训练 字符串长度(IO无敌)
    Java实现 蓝桥杯 算法训练 Remember the A La Mode(暴力)
    Java实现 蓝桥杯 算法训练 Remember the A La Mode(暴力)
    Java实现 蓝桥杯 算法训练 Remember the A La Mode(暴力)
  • 原文地址:https://www.cnblogs.com/hehe520/p/6330555.html
Copyright © 2011-2022 走看看