利用分析函数优化自连接

来源:互联网 发布:java 反编译 编辑:程序博客网 时间:2024/04/29 01:22

[html] view plaincopyprint?
  1. select distinct decode(length(a.category_id),  
  2.                                 5,  
  3.                                 decode(a.origin_type, 801, 888888, 999999),  
  4.                                 a.category_id) category_id,  
  5.                          a.notice_code,  
  6.                          a.treat_status,  
  7.                          lr.real_name as receiver_name,  
  8.                          f.send_code,  
  9.                          f.policy_code,  
  10.                          g.real_name agent_name,  
  11.                          f.organ_id,  
  12.                          f.dept_id,  
  13.                          a.policy_id,  
  14.                          a.change_id,  
  15.                          a.case_id,  
  16.                          a.group_policy_id,  
  17.                          a.fee_id,  
  18.                          a.auth_id,  
  19.                          a.pay_id,  
  20.                          cancel_appoint.appoint_time cancel_appoint_time,  
  21.                          a.insert_time,  
  22.                          a.send_time,  
  23.                          a.end_time,  
  24.                          f.agency_code,  
  25.                          a.REPLY_TIME,  
  26.                          a.REPLY_EMP_ID,  
  27.                          a.FIRST_DUTY,  
  28.                          a.NEED_SEND_PRINT,  
  29.                          11 source  
  30.            from t_policy_problem        a,  
  31.                 t_policy                f,  
  32.                 t_agent                 g,  
  33.                 t_letter_receiver       lr,  
  34.                 t_problem_category      pc,  
  35.                 t_policy_cancel_appoint cancel_appoint  
  36.           where f.agent_id = g.agent_id(+)  
  37.             and a.policy_id = f.policy_id(+)  
  38.             and lr.main_receiver = 'Y'  
  39.             and a.category_id = pc.category_id  
  40.             and a.item_id = lr.item_id  
  41.             and a.policy_id = cancel_appoint.policy_id(+)  
  42.             And a.Item_Id = (Select Max(item_id)  
  43.                                From t_Policy_Problem  
  44.                               Where notice_code = a.notice_code)  
  45.             and a.policy_id is not null  
  46.             and a.notice_code is not null  
  47.             and a.change_id is null  
  48.             and a.case_id is null  
  49.             and a.group_policy_id is null  
  50.             and a.origin_type not in (801, 802)  
  51.             and a.pay_id is null  
  52.             and a.category_id not in  
  53.                 (130103, 130104, 130102, 140102, 140101)  
  54.             and f.policy_type = 1  
  55.             and (a.fee_id is null or  
  56.                 (a.fee_id is not null and a.origin_type = 701))  
  57.             and f.organ_id in  
  58.                 (select distinct organ_id  
  59.                    from T_COMPANY_ORGAN  
  60.                   start with organ_id = '107'  
  61.                  connect by parent_id = prior organ_id)  
  62.             and pc.NEED_PRITN = 'Y'  
  63.   
  64.   
  65. SQL> select * from table(dbms_xplan.display);  
  66.   
  67. PLAN_TABLE_OUTPUT  
  68. --------------------------------------------------------------------------------------------------------  
  69. --------------------------------------------------------------------------------------------------------  
  70. | Id  | Operation                           |  Name                       | Rows  | Bytes | Cost (%CPU)|  
  71. --------------------------------------------------------------------------------------------------------  
  72. |   0 | SELECT STATEMENT                    |                             |     1 |   242 |   731   (1)|  
  73. |   1 |  SORT UNIQUE                        |                             |     1 |   242 |   729   (0)|  
  74. |*  2 |   FILTER                            |                             |       |       |            |  
  75. |*  3 |    HASH JOIN                        |                             |     1 |   242 |   714   (1)|  
  76. |   4 |     NESTED LOOPS                    |                             |     1 |   236 |   712   (1)|  
  77. |   5 |      NESTED LOOPS OUTER             |                             |     1 |   219 |   711   (1)|  
  78. |   6 |       NESTED LOOPS                  |                             |     1 |   203 |   710   (1)|  
  79. |   7 |        NESTED LOOPS                 |                             |     1 |   196 |   709   (1)|  
  80. |   8 |         NESTED LOOPS OUTER          |                             |     1 |   121 |   708   (1)|  
  81. |*  9 |          TABLE ACCESS FULL          | T_POLICY_PROBLEM            |     1 |   107 |   706   (0)|  
  82. |  10 |          TABLE ACCESS BY INDEX ROWID| T_POLICY_CANCEL_APPOINT     |     1 |    14 |     2  (50)|  
  83. |* 11 |           INDEX UNIQUE SCAN         | UK1_POLICY_CANCEL_APPOINT   |     1 |       |            |  
  84. |* 12 |         TABLE ACCESS BY INDEX ROWID | T_POLICY                    |     1 |    75 |     2  (50)|  
  85. |* 13 |          INDEX UNIQUE SCAN          | PK_T_POLICY                 |     1 |       |     1   (0)|  
  86. |* 14 |        TABLE ACCESS BY INDEX ROWID  | T_PROBLEM_CATEGORY          |     1 |     7 |     2  (50)|  
  87. |* 15 |         INDEX UNIQUE SCAN           | PK_T_PROBLEM_CATEGORY       |     1 |       |            |  
  88. |  16 |       TABLE ACCESS BY INDEX ROWID   | T_AGENT                     |     1 |    16 |     2  (50)|  
  89. |* 17 |        INDEX UNIQUE SCAN            | PK_T_AGENT                  |     1 |       |            |  
  90. |* 18 |      INDEX RANGE SCAN               | T_LETTER_RECEIVER_IDX_001   |     1 |    17 |     2   (0)|  
  91. |  19 |     VIEW                            | VW_NSO_1                    |     7 |    42 |            |  
  92. |* 20 |      CONNECT BY WITH FILTERING      |                             |       |       |            |  
  93. |  21 |       NESTED LOOPS                  |                             |       |       |            |  
  94. |* 22 |        INDEX UNIQUE SCAN            | PK_T_COMPANY_ORGAN          |     1 |     6 |            |  
  95. |  23 |        TABLE ACCESS BY USER ROWID   | T_COMPANY_ORGAN             |       |       |            |  
  96. |  24 |       NESTED LOOPS                  |                             |       |       |            |  
  97. |  25 |        BUFFER SORT                  |                             |     7 |    70 |            |  
  98. |  26 |         CONNECT BY PUMP             |                             |       |       |            |  
  99. |* 27 |        INDEX RANGE SCAN             | T_COMPANY_ORGAN_IDX_002     |     7 |    70 |     1   (0)|  
  100. |  28 |    SORT AGGREGATE                   |                             |     1 |    21 |            |  
  101. |  29 |     TABLE ACCESS BY INDEX ROWID     | T_POLICY_PROBLEM            |     1 |    21 |     2  (50)|  
  102. |* 30 |      INDEX RANGE SCAN               | IDX_POLICY_PROBLEM__N_CODE  |     1 |       |     3   (0)|  
  103. --------------------------------------------------------------------------------------------------------  
  104.   
  105. Predicate Information (identified by operation id):  
  106. ---------------------------------------------------  
  107.   
  108.    2 - filter("SYS_ALIAS_1"."ITEM_ID"= (SELECT /*+ */ MAX("T_POLICY_PROBLEM"."ITEM_ID") FROM  
  109.               "T_POLICY_PROBLEM" "T_POLICY_PROBLEM" WHERE "T_POLICY_PROBLEM"."NOTICE_CODE"=:B1))  
  110.    3 - access("F"."ORGAN_ID"="VW_NSO_1"."$nso_col_1")  
  111.    9 - filter("SYS_ALIAS_1"."POLICY_ID" IS NOT NULL AND "SYS_ALIAS_1"."NOTICE_CODE" IS NOT NULL AND  
  112.               "SYS_ALIAS_1"."CHANGE_ID" IS NULL AND "SYS_ALIAS_1"."CASE_ID" IS NULL AND  
  113.               "SYS_ALIAS_1"."GROUP_POLICY_ID" IS NULL AND TO_NUMBER("SYS_ALIAS_1"."ORIGIN_TYPE")<>801 AND  
  114.               TO_NUMBER("SYS_ALIAS_1"."ORIGIN_TYPE")<>802 AND "SYS_ALIAS_1"."PAY_ID" IS NULL AND  
  115.               "SYS_ALIAS_1"."CATEGORY_ID"<>130103 AND "SYS_ALIAS_1"."CATEGORY_ID"<>130104 AND  
  116.               "SYS_ALIAS_1"."CATEGORY_ID"<>130102 AND "SYS_ALIAS_1"."CATEGORY_ID"<>140102 AND  
  117.               "SYS_ALIAS_1"."CATEGORY_ID"<>140101 AND ("SYS_ALIAS_1"."FEE_ID" IS NULL OR "SYS_ALIAS_1"."FEE_ID" IS  
  118.               NOT NULL AND TO_NUMBER("SYS_ALIAS_1"."ORIGIN_TYPE")=701))  
  119.   11 - access("SYS_ALIAS_1"."POLICY_ID"="CANCEL_APPOINT"."POLICY_ID"(+))  
  120.   12 - filter(TO_NUMBER("F"."POLICY_TYPE")=1)  
  121.   13 - access("SYS_ALIAS_1"."POLICY_ID"="F"."POLICY_ID")  
  122.   14 - filter("PC"."NEED_PRITN"='Y')  
  123.   15 - access("SYS_ALIAS_1"."CATEGORY_ID"="PC"."CATEGORY_ID")  
  124.        filter("PC"."CATEGORY_ID"<>130103 AND "PC"."CATEGORY_ID"<>130104 AND "PC"."CATEGORY_ID"<>130102  
  125.               AND "PC"."CATEGORY_ID"<>140102 AND "PC"."CATEGORY_ID"<>140101)  
  126.   17 - access("F"."AGENT_ID"="G"."AGENT_ID"(+))  
  127.   18 - access("LR"."MAIN_RECEIVER"='Y' AND "SYS_ALIAS_1"."ITEM_ID"="LR"."ITEM_ID")  
  128.   20 - filter("T_COMPANY_ORGAN"."ORGAN_ID"='107')  
  129.   22 - access("T_COMPANY_ORGAN"."ORGAN_ID"='107')  
  130.   27 - access("T_COMPANY_ORGAN"."PARENT_ID"=NULL)  
  131.   30 - access("T_POLICY_PROBLEM"."NOTICE_CODE"=:B1)  
  132.   
  133. 64 rows selected.  
  134.   
  135.   
  136. Statistics  
  137. ----------------------------------------------------------  
  138.           7  recursive calls  
  139.           0  db block gets  
  140.     1626677  consistent gets  
  141.       30677  physical reads  
  142.         128  redo size  
  143.     2291351  bytes sent via SQL*Net to client  
  144.       13277  bytes received via SQL*Net from client  
  145.        1060  SQL*Net roundtrips to/from client  
  146.           6  sorts (memory)  
  147.           0  sorts (disk)  
  148.       15878  rows processed  


实际会返回15878行,但是执行计划上说返回1条记录,初学者可能会觉得是统计信息的问题(如果你觉得这个SQL跑得慢是统计信息不准,那么你就是初学者),其实不是这样的

因为有INDEX UNIQUE SCAN ,返回1条记录是正常的(不返回1条才不正常),另外第九步这里,它过滤条件太复杂,CBO在计算基数的时候也很容易把它算少,这里等于1

好了言归正传,这个SQL最坑爹的地方其实 是这个条件

 And a.Item_Id = (Select Max(item_id)
                               From t_Policy_Problem
                              Where notice_code = a.notice_code)

这里其实相当于 t_Policy_Problem 这个表做自连接,但是这个自连接很坑爹,会导致 t_Policy_Problem 表扫描2次,从执行计划上可以看出,第九步这里它做了一个全表扫描,然后在最后28,29.30 这3步走了索引,然后回表,最后它还要被FILTER过滤 ,恩 这个地方就是 这个SQL的性能瓶颈 那么SQL 改写如下:

[html] view plaincopyprint?
  1. WITH t_Policy_Problem_w AS  
  2. (SELECT tp.*,  
  3. max(item_id) OVER (PARTITION BY notice_code)  
  4. max_item_id  
  5. FROM t_Policy_Problem tp)  
  6. select distinct decode(length(a.category_id),  
  7.                                 5,  
  8.                                 decode(a.origin_type, 801, 888888, 999999),  
  9.                                 a.category_id) category_id,  
  10.                          a.notice_code,  
  11.                          a.treat_status,  
  12.                          lr.real_name as receiver_name,  
  13.                          f.send_code,  
  14.                          f.policy_code,  
  15.                          g.real_name agent_name,  
  16.                          f.organ_id,  
  17.                          f.dept_id,  
  18.                          a.policy_id,  
  19.                          a.change_id,  
  20.                          a.case_id,  
  21.                          a.group_policy_id,  
  22.                          a.fee_id,  
  23.                          a.auth_id,  
  24.                          a.pay_id,  
  25.                          cancel_appoint.appoint_time cancel_appoint_time,  
  26.                          a.insert_time,  
  27.                          a.send_time,  
  28.                          a.end_time,  
  29.                          f.agency_code,  
  30.                          a.REPLY_TIME,  
  31.                          a.REPLY_EMP_ID,  
  32.                          a.FIRST_DUTY,  
  33.                          a.NEED_SEND_PRINT,  
  34.                          11 source  
  35.            from t_Policy_Problem_w        a,  
  36.                 t_policy                f,  
  37.                 t_agent                 g,  
  38.                 t_letter_receiver       lr,  
  39.                 t_problem_category      pc,  
  40.                 t_policy_cancel_appoint cancel_appoint  
  41.           where   
  42.             a.item_id=a.max_item_id  
  43.             and f.agent_id = g.agent_id(+)  
  44.             and a.policy_id = f.policy_id(+)  
  45.             and lr.main_receiver = 'Y'  
  46.             and a.category_id = pc.category_id  
  47.             and a.item_id = lr.item_id  
  48.             and a.policy_id = cancel_appoint.policy_id(+)  
  49.             and a.policy_id is not null  
  50.             and a.notice_code is not null  
  51.             and a.change_id is null  
  52.             and a.case_id is null  
  53.             and a.group_policy_id is null  
  54.             and a.origin_type not in (801, 802)  
  55.             and a.pay_id is null  
  56.             and a.category_id not in  
  57.                 (130103, 130104, 130102, 140102, 140101)  
  58.             and f.policy_type = 1  
  59.             and (a.fee_id is null or  
  60.                 (a.fee_id is not null and a.origin_type = 701))  
  61.             and f.organ_id in  
  62.                 (select distinct organ_id  
  63.                    from T_COMPANY_ORGAN  
  64.                   start with organ_id = '107'  
  65.                  connect by parent_id = prior organ_id)  
  66.             and pc.NEED_PRITN = 'Y'  
  67.   
  68. ----------------------------------------------------------------------------------------------------------------  
  69. | Id  | Operation                            |  Name                      | Rows  | Bytes |TempSpc| Cost (%CPU)|  
  70. ----------------------------------------------------------------------------------------------------------------  
  71. |   0 | SELECT STATEMENT                     |                            | 21241 |  5289K|       | 17992   (0)|  
  72. |   1 |  SORT UNIQUE                         |                            | 21241 |  5289K|    11M| 17992   (0)|  
  73. |*  2 |   HASH JOIN                          |                            | 21241 |  5289K|  5192K| 17192   (1)|  
  74. |*  3 |    HASH JOIN OUTER                   |                            | 21248 |  4938K|  4856K| 16727   (1)|  
  75. |*  4 |     HASH JOIN OUTER                  |                            | 21248 |  4606K|  4568K| 15994   (1)|  
  76. |*  5 |      HASH JOIN                       |                            | 21248 |  4316K|       | 15920   (1)|  
  77. |*  6 |       TABLE ACCESS FULL              | T_PROBLEM_CATEGORY         |   371 |  2597 |       |     4   (0)|  
  78. |*  7 |       HASH JOIN                      |                            | 29477 |  5786K|  5712K| 15915   (1)|  
  79. |*  8 |        HASH JOIN                     |                            | 62888 |  4974K|       |  9575   (1)|  
  80. |   9 |         VIEW                         | VW_NSO_1                   |     7 |    42 |       |            |  
  81. |* 10 |          CONNECT BY WITH FILTERING   |                            |       |       |       |            |  
  82. |  11 |           NESTED LOOPS               |                            |       |       |       |            |  
  83. |* 12 |            INDEX UNIQUE SCAN         | PK_T_COMPANY_ORGAN         |     1 |     6 |       |            |  
  84. |  13 |            TABLE ACCESS BY USER ROWID| T_COMPANY_ORGAN            |       |       |       |            |  
  85. |  14 |           NESTED LOOPS               |                            |       |       |       |            |  
  86. |  15 |            BUFFER SORT               |                            |     7 |    70 |       |            |  
  87. |  16 |             CONNECT BY PUMP          |                            |       |       |       |            |  
  88. |* 17 |            INDEX RANGE SCAN          | T_COMPANY_ORGAN_IDX_002    |     7 |    70 |       |     1   (0)|  
  89. |* 18 |         TABLE ACCESS FULL            | T_POLICY                   |   637K|    45M|       |  9569   (0)|  
  90. |* 19 |        VIEW                          |                            |   300K|    34M|       |            |  
  91. |  20 |         WINDOW SORT                  |                            |   300K|    30M|    88M|  5648   (0)|  
  92. |  21 |          TABLE ACCESS FULL           | T_POLICY_PROBLEM           |   300K|    30M|       |   706   (0)|  
  93. |  22 |      TABLE ACCESS FULL               | T_POLICY_CANCEL_APPOINT    |    86 |  1204 |       |     2   (0)|  
  94. |  23 |     TABLE ACCESS FULL                | T_AGENT                    | 88982 |  1390K|       |   619   (0)|  
  95. |* 24 |    INDEX FAST FULL SCAN              | T_LETTER_RECEIVER_IDX_001  |   300K|  4987K|       |   251   (0)|  
  96. ----------------------------------------------------------------------------------------------------------------  
  97.   
  98. Predicate Information (identified by operation id):  
  99. ---------------------------------------------------  
  100.   
  101.    2 - access("A"."ITEM_ID"="LR"."ITEM_ID")  
  102.    3 - access("F"."AGENT_ID"="G"."AGENT_ID"(+))  
  103.    4 - access("A"."POLICY_ID"="CANCEL_APPOINT"."POLICY_ID"(+))  
  104.    5 - access("A"."CATEGORY_ID"="PC"."CATEGORY_ID")  
  105.    6 - filter("PC"."NEED_PRITN"='Y' AND "PC"."CATEGORY_ID"<>130103 AND "PC"."CATEGORY_ID"<>130104 AND  
  106.               "PC"."CATEGORY_ID"<>130102 AND "PC"."CATEGORY_ID"<>140102 AND "PC"."CATEGORY_ID"<>140101)  
  107.    7 - access("A"."POLICY_ID"="F"."POLICY_ID")  
  108.    8 - access("F"."ORGAN_ID"="VW_NSO_1"."$nso_col_1")  
  109.   10 - filter("T_COMPANY_ORGAN"."ORGAN_ID"='107')  
  110.   12 - access("T_COMPANY_ORGAN"."ORGAN_ID"='107')  
  111.   17 - access("T_COMPANY_ORGAN"."PARENT_ID"=NULL)  
  112.   18 - filter(TO_NUMBER("F"."POLICY_TYPE")=1)  
  113.   19 - filter("A"."ITEM_ID"="A"."MAX_ITEM_ID" AND "A"."POLICY_ID" IS NOT NULL AND "A"."NOTICE_CODE" IS NOT NULL  
  114.               AND "A"."CHANGE_ID" IS NULL AND "A"."CASE_ID" IS NULL AND "A"."GROUP_POLICY_ID" IS NULL AND  
  115.               TO_NUMBER("A"."ORIGIN_TYPE")<>801 AND TO_NUMBER("A"."ORIGIN_TYPE")<>802 AND "A"."PAY_ID" IS NULL AND  
  116.               "A"."CATEGORY_ID"<>130103 AND "A"."CATEGORY_ID"<>130104 AND "A"."CATEGORY_ID"<>130102 AND  
  117.               "A"."CATEGORY_ID"<>140102 AND "A"."CATEGORY_ID"<>140101 AND ("A"."FEE_ID" IS NULL OR "A"."FEE_ID" IS NOT NULL  
  118.               AND TO_NUMBER("A"."ORIGIN_TYPE")=701))  
  119.   24 - filter("LR"."MAIN_RECEIVER"='Y')  
  120.   
  121. 53 rows selected.  
  122.   
  123. Statistics  
  124. ----------------------------------------------------------  
  125.           0  recursive calls  
  126.           0  db block gets  
  127.      115995  consistent gets  
  128.       42204  physical reads  
  129.           0  redo size  
  130.     2182416  bytes sent via SQL*Net to client  
  131.       13289  bytes received via SQL*Net from client  
  132.        1060  SQL*Net roundtrips to/from client  
  133.           7  sorts (memory)  
  134.           0  sorts (disk)  
  135.       15879  rows processed  


利用分析函数MAX OVER (PARTITION BY) 干掉 那个自连接,减少表访问次数,干掉那个FILTER ,现在逻辑读降低到了115995,性能提升了近15倍 
这个SQL还有进一步优化的空间,另外这个SQL也还有需要改写的地方,不过那些太简单了 就不说了,其实以前盖尔发的SQL也有

 And a.Item_Id = (Select Max(item_id)
                               From t_Policy_Problem
                              Where notice_code = a.notice_code)

不过当时没给他改SQL 呵呵,当时太懒了,今天第一条上班心情不错 加上时间充裕,就搞搞吧

通过这个案例,你要学到的就是自连接的优化方法,利用分析函数干掉自连接,减少表访问次数。


http://blog.csdn.net/robinson1988/article/details/7219958

原创粉丝点击