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