帮盖尔优化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_modefrom 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 gwhere tpc.change_id = tpf.change_idand tpf.policy_id = d.policy_idand tcm.policy_id = tpc.policy_idand tpf.receiv_status = 1 and tpf.fee_status = 1and tpf.payment_id is nulland tpf.fee_type = c.type_idand tpf.pay_mode = g.mode_idand d.company_id = e.company_id(+)and d.applicant_id = f.customer_id(+)and tpf.organ_id in(select organ_idfrom t_company_organstart 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_codeorder by change_id, fee_typeSQL> 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 selectedStatistics ----------------------------------------------------------21 recursive calls0 db block gets125082 consistent gets21149 physical reads0 redo size2448 bytes sent via SQL*Net to client656 bytes received via SQL*Net from client2 SQL*Net roundtrips to/from client4 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,禁止子查詢擴展
最終這個SQL能在1秒以內跑完,邏輯讀下降到2817 ,到此我就沒繼續優化了,這個時候停止優化吧,別的了強迫優化癥
這個優化案例很簡單,我都不好意思貼在博客上,通過這個文章你要學到的就是,如果子查詢返回數據很少,那么不妨讓它走filter????????
轉載于:https://www.cnblogs.com/hehe520/archive/2011/11/29/6330557.html
總結
以上是生活随笔為你收集整理的帮盖尔优化SQL-----子查询优化的经典案例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Jdom的SAXBuilder解析Str
- 下一篇: 利用 IHttpHandler 自定义