Optimize self-connection using analysis functions

Source: Internet
Author: User
Tags sorts

The first day of spring festival is also a headache. Geer sent me another SQL statement. He said that the SQL dB file sequential read is very high and it takes 120 seconds to run, I can help optimize the logic read by 1626677. The SQL statement is as follows:

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.organ_id in                (select distinct organ_id                   from T_COMPANY_ORGAN                  start with organ_id = '107'                 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 |   242 |   731   (1)||   1 |  SORT UNIQUE                        |                             |     1 |   242 |   729   (0)||*  2 |   FILTER                            |                             |       |       |            ||*  3 |    HASH JOIN                        |                             |     1 |   242 |   714   (1)||   4 |     NESTED LOOPS                    |                             |     1 |   236 |   712   (1)||   5 |      NESTED LOOPS OUTER             |                             |     1 |   219 |   711   (1)||   6 |       NESTED LOOPS                  |                             |     1 |   203 |   710   (1)||   7 |        NESTED LOOPS                 |                             |     1 |   196 |   709   (1)||   8 |         NESTED LOOPS OUTER          |                             |     1 |   121 |   708   (1)||*  9 |          TABLE ACCESS FULL          | T_POLICY_PROBLEM            |     1 |   107 |   706   (0)||  10 |          TABLE ACCESS BY INDEX ROWID| T_POLICY_CANCEL_APPOINT     |     1 |    14 |     2  (50)||* 11 |           INDEX UNIQUE SCAN         | UK1_POLICY_CANCEL_APPOINT   |     1 |       |            ||* 12 |         TABLE ACCESS BY INDEX ROWID | T_POLICY                    |     1 |    75 |     2  (50)||* 13 |          INDEX UNIQUE SCAN          | PK_T_POLICY                 |     1 |       |     1   (0)||* 14 |        TABLE ACCESS BY INDEX ROWID  | T_PROBLEM_CATEGORY          |     1 |     7 |     2  (50)||* 15 |         INDEX UNIQUE SCAN           | PK_T_PROBLEM_CATEGORY       |     1 |       |            ||  16 |       TABLE ACCESS BY INDEX ROWID   | T_AGENT                     |     1 |    16 |     2  (50)||* 17 |        INDEX UNIQUE SCAN            | PK_T_AGENT                  |     1 |       |            ||* 18 |      INDEX RANGE SCAN               | T_LETTER_RECEIVER_IDX_001   |     1 |    17 |     2   (0)||  19 |     VIEW                            | VW_NSO_1                    |     7 |    42 |            ||* 20 |      CONNECT BY WITH FILTERING      |                             |       |       |            ||  21 |       NESTED LOOPS                  |                             |       |       |            ||* 22 |        INDEX UNIQUE SCAN            | PK_T_COMPANY_ORGAN          |     1 |     6 |            ||  23 |        TABLE ACCESS BY USER ROWID   | T_COMPANY_ORGAN             |       |       |            ||  24 |       NESTED LOOPS                  |                             |       |       |            ||  25 |        BUFFER SORT                  |                             |     7 |    70 |            ||  26 |         CONNECT BY PUMP             |                             |       |       |            ||* 27 |        INDEX RANGE SCAN             | T_COMPANY_ORGAN_IDX_002     |     7 |    70 |     1   (0)||  28 |    SORT AGGREGATE                   |                             |     1 |    21 |            ||  29 |     TABLE ACCESS BY INDEX ROWID     | T_POLICY_PROBLEM            |     1 |    21 |     2  (50)||* 30 |      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_1"."$nso_col_1")   9 - 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 - access("SYS_ALIAS_1"."POLICY_ID"="CANCEL_APPOINT"."POLICY_ID"(+))  12 - filter(TO_NUMBER("F"."POLICY_TYPE")=1)  13 - access("SYS_ALIAS_1"."POLICY_ID"="F"."POLICY_ID")  14 - filter("PC"."NEED_PRITN"='Y')  15 - 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)  17 - access("F"."AGENT_ID"="G"."AGENT_ID"(+))  18 - access("LR"."MAIN_RECEIVER"='Y' AND "SYS_ALIAS_1"."ITEM_ID"="LR"."ITEM_ID")  20 - filter("T_COMPANY_ORGAN"."ORGAN_ID"='107')  22 - access("T_COMPANY_ORGAN"."ORGAN_ID"='107')  27 - access("T_COMPANY_ORGAN"."PARENT_ID"=NULL)  30 - access("T_POLICY_PROBLEM"."NOTICE_CODE"=:B1)64 rows selected.Statistics----------------------------------------------------------          7  recursive calls          0  db block gets    1626677  consistent gets      30677  physical reads        128  redo size    2291351  bytes sent via SQL*Net to client      13277  bytes received via SQL*Net from client       1060  SQL*Net roundtrips to/from client          6  sorts (memory)          0  sorts (disk)      15878  rows processed

Actually, 15878 rows will be returned, but one record will be returned in the execution plan. This may be a statistical problem for beginners (if you think this SQL statement is slow, the statistics are inaccurate, so you are a beginner .)

Because index unique scan exists, it is normal to return one record (it is not normal if one record is not returned). In addition, in Step 9, the filtering conditions are too complex, when calculating the base, it is easy for CBO to calculate less. Here it is equal to 1.

Let's get down to the point where this SQL statement is actually the most boring

And a. item_id = (select max (item_id)
From t_policy_problem
Where notice_code = A. notice_code)

This is actually equivalent to the t_policy_problem table for self-join, but this self-join is very poor, it will cause t_policy_problem table to scan twice, as shown in the execution plan, in the ninth step, it performs a full table scan. Then, in the last step 28 and 29.30, it performs an index, then returns to the table, and finally filters the index, well, this is the performance bottleneck of this SQL statement, so the SQL rewrite is as follows:

WITH t_Policy_Problem_w AS(SELECT tp.*,max(item_id) OVER (PARTITION BY notice_code)max_item_idFROM t_Policy_Problem tp)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_w        a,                t_policy                f,                t_agent                 g,                t_letter_receiver       lr,                t_problem_category      pc,                t_policy_cancel_appoint cancel_appoint          where             a.item_id=a.max_item_id            and 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.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.organ_id in                (select distinct organ_id                   from T_COMPANY_ORGAN                  start with organ_id = '107'                 connect by parent_id = prior organ_id)            and pc.NEED_PRITN = 'Y'----------------------------------------------------------------------------------------------------------------| Id  | Operation                            |  Name                      | Rows  | Bytes |TempSpc| Cost (%CPU)|----------------------------------------------------------------------------------------------------------------|   0 | SELECT STATEMENT                     |                            | 21241 |  5289K|       | 17992   (0)||   1 |  SORT UNIQUE                         |                            | 21241 |  5289K|    11M| 17992   (0)||*  2 |   HASH JOIN                          |                            | 21241 |  5289K|  5192K| 17192   (1)||*  3 |    HASH JOIN OUTER                   |                            | 21248 |  4938K|  4856K| 16727   (1)||*  4 |     HASH JOIN OUTER                  |                            | 21248 |  4606K|  4568K| 15994   (1)||*  5 |      HASH JOIN                       |                            | 21248 |  4316K|       | 15920   (1)||*  6 |       TABLE ACCESS FULL              | T_PROBLEM_CATEGORY         |   371 |  2597 |       |     4   (0)||*  7 |       HASH JOIN                      |                            | 29477 |  5786K|  5712K| 15915   (1)||*  8 |        HASH JOIN                     |                            | 62888 |  4974K|       |  9575   (1)||   9 |         VIEW                         | VW_NSO_1                   |     7 |    42 |       |            ||* 10 |          CONNECT BY WITH FILTERING   |                            |       |       |       |            ||  11 |           NESTED LOOPS               |                            |       |       |       |            ||* 12 |            INDEX UNIQUE SCAN         | PK_T_COMPANY_ORGAN         |     1 |     6 |       |            ||  13 |            TABLE ACCESS BY USER ROWID| T_COMPANY_ORGAN            |       |       |       |            ||  14 |           NESTED LOOPS               |                            |       |       |       |            ||  15 |            BUFFER SORT               |                            |     7 |    70 |       |            ||  16 |             CONNECT BY PUMP          |                            |       |       |       |            ||* 17 |            INDEX RANGE SCAN          | T_COMPANY_ORGAN_IDX_002    |     7 |    70 |       |     1   (0)||* 18 |         TABLE ACCESS FULL            | T_POLICY                   |   637K|    45M|       |  9569   (0)||* 19 |        VIEW                          |                            |   300K|    34M|       |            ||  20 |         WINDOW SORT                  |                            |   300K|    30M|    88M|  5648   (0)||  21 |          TABLE ACCESS FULL           | T_POLICY_PROBLEM           |   300K|    30M|       |   706   (0)||  22 |      TABLE ACCESS FULL               | T_POLICY_CANCEL_APPOINT    |    86 |  1204 |       |     2   (0)||  23 |     TABLE ACCESS FULL                | T_AGENT                    | 88982 |  1390K|       |   619   (0)||* 24 |    INDEX FAST FULL SCAN              | T_LETTER_RECEIVER_IDX_001  |   300K|  4987K|       |   251   (0)|----------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------   2 - access("A"."ITEM_ID"="LR"."ITEM_ID")   3 - access("F"."AGENT_ID"="G"."AGENT_ID"(+))   4 - access("A"."POLICY_ID"="CANCEL_APPOINT"."POLICY_ID"(+))   5 - access("A"."CATEGORY_ID"="PC"."CATEGORY_ID")   6 - filter("PC"."NEED_PRITN"='Y' AND "PC"."CATEGORY_ID"<>130103 AND "PC"."CATEGORY_ID"<>130104 AND              "PC"."CATEGORY_ID"<>130102 AND "PC"."CATEGORY_ID"<>140102 AND "PC"."CATEGORY_ID"<>140101)   7 - access("A"."POLICY_ID"="F"."POLICY_ID")   8 - access("F"."ORGAN_ID"="VW_NSO_1"."$nso_col_1")  10 - filter("T_COMPANY_ORGAN"."ORGAN_ID"='107')  12 - access("T_COMPANY_ORGAN"."ORGAN_ID"='107')  17 - access("T_COMPANY_ORGAN"."PARENT_ID"=NULL)  18 - filter(TO_NUMBER("F"."POLICY_TYPE")=1)  19 - filter("A"."ITEM_ID"="A"."MAX_ITEM_ID" 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              TO_NUMBER("A"."ORIGIN_TYPE")<>801 AND TO_NUMBER("A"."ORIGIN_TYPE")<>802 AND "A"."PAY_ID" IS NULL AND              "A"."CATEGORY_ID"<>130103 AND "A"."CATEGORY_ID"<>130104 AND "A"."CATEGORY_ID"<>130102 AND              "A"."CATEGORY_ID"<>140102 AND "A"."CATEGORY_ID"<>140101 AND ("A"."FEE_ID" IS NULL OR "A"."FEE_ID" IS NOT NULL              AND TO_NUMBER("A"."ORIGIN_TYPE")=701))  24 - filter("LR"."MAIN_RECEIVER"='Y')53 rows selected.Statistics----------------------------------------------------------          0  recursive calls          0  db block gets     115995  consistent gets      42204  physical reads          0  redo size    2182416  bytes sent via SQL*Net to client      13289  bytes received via SQL*Net from client       1060  SQL*Net roundtrips to/from client          7  sorts (memory)          0  sorts (disk)      15879  rows processed

The analysis function max over (partition by) is used to remove the self-join, reduce the number of table accesses, and kill the filter. Now the logical read is reduced to 115995, and the performance is improved by nearly 15 times.
There is still room for further optimization of this SQL statement. In addition, this SQL statement also needs to be rewritten. However, if it is too simple, it will not be said. In fact, there are also SQL statements sent by Gael in the past.

And a. item_id = (select max (item_id)
From t_policy_problem
Where notice_code = A. notice_code)

However, I didn't change the SQL statement for him at the time. I was too lazy at the time. Today I am in a good mood at work and have plenty of time. Let's do it.

In this case, you need to learn the self-join optimization method. You can use the analysis function to remove the self-join and reduce the number of table accesses.

 

 

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.