子查询里面有树形查询,子查询选择使用in/exists需要特别留意

来源:互联网 发布:java工程师jd 编辑:程序博客网 时间:2024/04/30 15:19

今天下午盖尔又发来一条坑爹的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需要特别留意