zoukankan      html  css  js  c++  java
  • DBLINK引起的SQL性能问题

    最近发现报表系统上有一存储过程越来越慢,在数据库中查询后,发现有以下条SQL

    --优化前:耗时>1h
      select c.policyno,
               c.endorseno,
               r.item_code,
               sum(r.outstanding_amount - r.settled_amount - r.offset_amount) OS_amount
          from c_reserve_list@aclaim r
          left join c_claim@aclaim c
            on c.claimno = r.claim_no
         where r.busi_phase in
               (select max(busi_phase)
                  from rpt_st.c_reserve_list
                 where claim_no = r.claim_no
                   and last_modify_date =
                       (select max(last_modify_date)
                          from rpt_st.c_reserve_list
                         where claim_no = r.claim_no
                           and last_modify_date < to_date(V_ENDDATE, 'yyyymmdd')))
           and r.count =
               (select max(count)
                  from rpt_st.c_reserve_list
                 where claim_no = r.claim_no
                   and busi_phase = r.busi_phase
                   and count in
                       (select 
                         count
                          from rpt_st.c_reserve_list
                         where claim_no = r.claim_no
                           and busi_phase = r.busi_phase
                           and last_modify_date < to_date(V_ENDDATE, 'yyyymmdd')))
         group by c.policyno, c.endorseno, r.item_code;
    --执行计划
    Plan hash value: 3027187983
    
    -------------------------------------------------------------------------------------------------------------------
    | Id  | Operation                | Name           | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Inst   |IN-OUT|
    -------------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT         |                | 22383 |  6251K|       |  6751M  (1)|999:59:59 |        |      |
    |   1 |  HASH GROUP BY           |                | 22383 |  6251K|   408G|  6751M  (1)|999:59:59 |        |      |
    |*  2 |   FILTER                 |                |       |       |       |            |          |        |      |
    |*  3 |    HASH JOIN             |                |  1417M|   377G|    23M|    97M  (1)|324:16:14 |        |      |
    |*  4 |     HASH JOIN RIGHT OUTER|                |   144K|    22M|       |   605   (2)| 00:00:08 |        |      |
    |   5 |      REMOTE              | C_CLAIM        |  5527 |   356K|       |   153   (1)| 00:00:02 | AUTOC~ | R->S |
    |   6 |      REMOTE              | C_RESERVE_LIST |   144K|    12M|       |   450   (2)| 00:00:06 | AUTOC~ | R->S |
    |   7 |     VIEW                 | VW_SQ_1        |  1417M|   166G|       |    88M  (1)|293:20:25 |        |      |
    |   8 |      HASH GROUP BY       |                |  1417M|   248G|   601G|    88M  (1)|293:20:25 |        |      |
    |*  9 |       HASH JOIN          |                |  1735M|   303G|    14M| 19266  (88)| 00:03:52 |        |      |
    |  10 |        REMOTE            | C_RESERVE_LIST |   144K|    12M|       |   450   (2)| 00:00:06 | NEWAU~ | R->S |
    |  11 |        REMOTE            | C_RESERVE_LIST |   144K|    12M|       |   450   (2)| 00:00:06 | NEWAU~ | R->S |
    |  12 |    SORT AGGREGATE        |                |     1 |    61 |       |            |          |        |      |
    |* 13 |     FILTER               |                |       |       |       |            |          |        |      |
    |  14 |      REMOTE              | C_RESERVE_LIST |     1 |    61 |       |     3   (0)| 00:00:01 | NEWAU~ | R->S |
    |  15 |      SORT AGGREGATE      |                |     1 |    51 |       |            |          |        |      |
    |  16 |       REMOTE             | C_RESERVE_LIST |    32 |  1632 |       |     3   (0)| 00:00:01 | NEWAU~ | R->S |
    -------------------------------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - filter("R"."BUSI_PHASE"= (SELECT MAX("BUSI_PHASE") FROM  "A1" WHERE "LAST_MODIFY_DATE"= (SELECT 
                  MAX("LAST_MODIFY_DATE") FROM  "A1" WHERE "CLAIM_NO"=:B1 AND "LAST_MODIFY_DATE"<TO_DATE(' 2017-06-26 
                  00:00:00', 'syyyy-mm-dd hh24:mi:ss')) AND "CLAIM_NO"=:B2))
       3 - access("R"."COUNT"="VW_COL_1" AND "CLAIM_NO"="R"."CLAIM_NO" AND "BUSI_PHASE"="R"."BUSI_PHASE" AND 
                  "CLAIM_NO"="R"."CLAIM_NO" AND "BUSI_PHASE"="R"."BUSI_PHASE")
       4 - access("C"."CLAIMNO"(+)="R"."CLAIM_NO")
       9 - access("COUNT"="COUNT")
      13 - filter("LAST_MODIFY_DATE"= (SELECT MAX("LAST_MODIFY_DATE") FROM  "A1" WHERE "CLAIM_NO"=:B1 AND 
                  "LAST_MODIFY_DATE"<TO_DATE(' 2017-06-26 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))
    
    Remote SQL Information (identified by operation id):
    ----------------------------------------------------
    
       5 - SELECT "CLAIMNO","POLICYNO","ENDORSENO" FROM "C_CLAIM" "C" (accessing 'aclaim' )
    
       6 - SELECT "CLAIM_NO","ITEM_CODE","OUTSTANDING_AMOUNT","SETTLED_AMOUNT","OFFSET_AMOUNT","BUSI_PHASE","CO
           UNT" FROM "C_RESERVE_LIST" "SYS_ALIAS_2" (accessing 'aclaim' )
    
      10 - SELECT "CLAIM_NO","LAST_MODIFY_DATE","BUSI_PHASE","COUNT" FROM "aclaim"."C_RESERVE_LIST" "A2" 
            WHERE "LAST_MODIFY_DATE"<:1 (accessing 'NEWaclaim' )
    
      11 - SELECT "CLAIM_NO","BUSI_PHASE","COUNT" FROM "aclaim"."C_RESERVE_LIST" "A1" (accessing 
            'NEWaclaim' )
    
      14 - SELECT "CLAIM_NO","LAST_MODIFY_DATE","BUSI_PHASE" FROM "aclaim"."C_RESERVE_LIST" "A1" WHERE 
            "CLAIM_NO"=:1 (accessing 'NEWaclaim' )
    
      16 - SELECT "CLAIM_NO","LAST_MODIFY_DATE" FROM "aclaim"."C_RESERVE_LIST" "A1" WHERE "CLAIM_NO"=:1 AND 
            "LAST_MODIFY_DATE"<:2 (accessing 'NEWaclaim' )
    

    分析

    --在以上执行计划中可以看出该SQL,查询的都是远程表。所以可以改写成以下形式,然后在远程库直接执行。
     select  c.policyno,
               c.endorseno,
               r.item_code,
               sum(r.outstanding_amount - r.settled_amount - r.offset_amount) OS_amount
          from aclaim.c_reserve_list r
          left join aclaim.c_claim c
            on c.claimno = r.claim_no
         where r.busi_phase in
               (select max(busi_phase)
                  from aclaim.c_reserve_list
                 where claim_no = r.claim_no
                   and last_modify_date =
                       (select max(last_modify_date)
                          from aclaim.c_reserve_list
                         where claim_no = r.claim_no
                           and last_modify_date < to_date(20170626, 'yyyymmdd')))
           and r.count =
               (select max(count)
                  from aclaim.c_reserve_list
                 where claim_no = r.claim_no
                   and busi_phase = r.busi_phase
                   and count in
                       (select 
                         count
                          from aclaim.c_reserve_list
                         where claim_no = r.claim_no
                           and busi_phase = r.busi_phase
                           and last_modify_date < to_date(20170626, 'yyyymmdd')))
         group by c.policyno, c.endorseno, r.item_code;
    
    
    --执行计划如下:    
    
    Plan hash value: 897376705
    
    ------------------------------------------------------------------------------------------------------
    | Id  | Operation                 | Name             | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
    ------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT          |                  | 22383 |  1508K|       |    15M  (2)| 52:55:06 |
    |   1 |  HASH GROUP BY            |                  | 22383 |  1508K|    22M|    15M  (2)| 52:55:06 |
    |*  2 |   FILTER                  |                  |       |       |       |            |          |
    |*  3 |    HASH JOIN RIGHT OUTER  |                  |   144K|  9723K|       |   536   (3)| 00:00:07 |
    |   4 |     VIEW                  | index$_join$_002 |  5527 |   161K|       |    83   (0)| 00:00:02 |
    |*  5 |      HASH JOIN            |                  |       |       |       |            |          |
    |   6 |       INDEX FAST FULL SCAN| IDX_C_CLAIM_03   |  5527 |   161K|       |    46   (0)| 00:00:01 |
    |   7 |       INDEX FAST FULL SCAN| PK_C_CLAIM       |  5527 |   161K|       |    36   (0)| 00:00:01 |
    |   8 |     TABLE ACCESS FULL     | C_RESERVE_LIST   |   144K|  5496K|       |   450   (2)| 00:00:06 |
    |   9 |    SORT AGGREGATE         |                  |     1 |    24 |       |            |          |
    |* 10 |     FILTER                |                  |       |       |       |            |          |
    |* 11 |      TABLE ACCESS FULL    | C_RESERVE_LIST   |    32 |   768 |       |   449   (2)| 00:00:06 |
    |  12 |      SORT AGGREGATE       |                  |     1 |    21 |       |            |          |
    |* 13 |       TABLE ACCESS FULL   | C_RESERVE_LIST   |    32 |   672 |       |   449   (2)| 00:00:06 |
    |  14 |        SORT AGGREGATE     |                  |     1 |    46 |       |            |          |
    |* 15 |         HASH JOIN         |                  |     3 |   138 |       |   901   (3)| 00:00:11 |
    |* 16 |          TABLE ACCESS FULL| C_RESERVE_LIST   |     2 |    54 |       |   450   (2)| 00:00:06 |
    |* 17 |          TABLE ACCESS FULL| C_RESERVE_LIST   |     2 |    38 |       |   450   (2)| 00:00:06 |
    ------------------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - filter("R"."BUSI_PHASE"= (SELECT MAX("BUSI_PHASE") FROM "aclaim"."C_RESERVE_LIST" 
                  "C_RESERVE_LIST" WHERE "LAST_MODIFY_DATE"= (SELECT MAX("LAST_MODIFY_DATE") FROM 
                  "aclaim"."C_RESERVE_LIST" "C_RESERVE_LIST" WHERE "CLAIM_NO"=:B1 AND 
                  "LAST_MODIFY_DATE"<TO_DATE(' 2017-06-26 00:00:00', 'syyyy-mm-dd hh24:mi:ss')) AND 
                  "CLAIM_NO"=:B2) AND "R"."COUNT"= (SELECT MAX("COUNT") FROM "aclaim"."C_RESERVE_LIST" 
                  "C_RESERVE_LIST","aclaim"."C_RESERVE_LIST" "C_RESERVE_LIST" WHERE "CLAIM_NO"=:B3 AND 
                  "BUSI_PHASE"=:B4 AND "LAST_MODIFY_DATE"<TO_DATE(' 2017-06-26 00:00:00', 'syyyy-mm-dd 
                  hh24:mi:ss') AND "COUNT"="COUNT" AND "CLAIM_NO"=:B5 AND "BUSI_PHASE"=:B6))
       3 - access("C"."CLAIMNO"(+)="R"."CLAIM_NO")
       5 - access(ROWID=ROWID)
      10 - filter("LAST_MODIFY_DATE"= (SELECT MAX("LAST_MODIFY_DATE") FROM 
                  "aclaim"."C_RESERVE_LIST" "C_RESERVE_LIST" WHERE "CLAIM_NO"=:B1 AND 
                  "LAST_MODIFY_DATE"<TO_DATE(' 2017-06-26 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))
      11 - filter("CLAIM_NO"=:B1)
      13 - filter("CLAIM_NO"=:B1 AND "LAST_MODIFY_DATE"<TO_DATE(' 2017-06-26 00:00:00', 
                  'syyyy-mm-dd hh24:mi:ss'))
      15 - access("COUNT"="COUNT")
      16 - filter("CLAIM_NO"=:B1 AND "BUSI_PHASE"=:B2 AND "LAST_MODIFY_DATE"<TO_DATE(' 2017-06-26 
                  00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
      17 - filter("CLAIM_NO"=:B1 AND "BUSI_PHASE"=:B2)
    
    
    --执行计划中有filter关键字且有两个子级,一般来说是很耗费性能。
    
    --如果不进行改写,根据自己的经验,最有效的方式就是在执行计划中谓词信息里找出有绑定变量的字段并建立索引。
    
    --所以建立如下索引:
     create index IDX_C_RESERVE_LIST_TEST on C_RESERVE_LIST(CLAIM_NO,BUSI_PHASE,LAST_MODIFY_DATE);
    

    执行SQL,10s内能返回全部结果。

    但是,在报表库上运行时,发现SQL的性能还是没改善。

    再次分析执行计划:

    发现此sql运行时,采用多个dblink访问远程库。查看dblink的元数据:

     CREATE OR REPLACE SYNONYM "rpt_st"."C_RESERVE_LIST" FOR "aclaim"."C_RESERVE_LIST"@"NEWaclaim"; 
     create public database link aclaim    connect to aclaim using 'DOICLC';
     create public database link NEWaclaim connect to aclaim using 'DOICLC';

    发现两个DBLINK都是访问AUTOCLAIM用户下的表。

    这种方式很容易造成sql不能走正确执行计划,所以可以把sql中的dblink改写成同一个。

    再次执行,10s内能返回全部结果。

    SELECT C.POLICYNO,
             C.ENDORSENO,
             R.ITEM_CODE,
             SUM(R.OUTSTANDING_AMOUNT - R.SETTLED_AMOUNT - R.OFFSET_AMOUNT) OS_AMOUNT
        FROM rpt_st.C_RESERVE_LIST R
        LEFT JOIN rpt_st.C_CLAIM C
          ON C.CLAIMNO = R.CLAIM_NO
       WHERE R.BUSI_PHASE IN
             (SELECT MAX(BUSI_PHASE)
                FROM rpt_st.C_RESERVE_LIST
               WHERE CLAIM_NO = R.CLAIM_NO
                 AND LAST_MODIFY_DATE =
                     (SELECT MAX(LAST_MODIFY_DATE)
                        FROM rpt_st.C_RESERVE_LIST
                       WHERE CLAIM_NO = R.CLAIM_NO
                         AND LAST_MODIFY_DATE < TO_DATE('20170626', 'yyyymmdd')))
         AND R.COUNT =
             (SELECT MAX(COUNT)
                FROM rpt_st.C_RESERVE_LIST
               WHERE CLAIM_NO = R.CLAIM_NO
                 AND BUSI_PHASE = R.BUSI_PHASE
                 AND COUNT IN
                     (SELECT  COUNT
                        FROM rpt_st.C_RESERVE_LIST
                       WHERE CLAIM_NO = R.CLAIM_NO
                         AND BUSI_PHASE = R.BUSI_PHASE
                         AND LAST_MODIFY_DATE < TO_DATE('20170626', 'yyyymmdd')))
       GROUP BY C.POLICYNO, C.ENDORSENO, R.ITEM_CODE
    
    Plan hash value: 2524269579
    
    -------------------------------------------------------------------------------------------------------------------------------
    | Id  | Operation                          | Name                    | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Inst   |
    -------------------------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT REMOTE            |                         | 22383 |  1508K|       |   109K  (1)| 00:21:55 |        |
    |   1 |  HASH GROUP BY                     |                         | 22383 |  1508K|    22M|   109K  (1)| 00:21:55 |        |
    |*  2 |   FILTER                           |                         |       |       |       |            |          |        |
    |*  3 |    HASH JOIN RIGHT OUTER           |                         |   144K|  9723K|       |   536   (3)| 00:00:07 |        |
    |   4 |     VIEW                           | index$_join$_002        |  5527 |   161K|       |    83   (0)| 00:00:02 | DOICLC |
    |*  5 |      HASH JOIN                     |                         |       |       |       |            |          |        |
    |   6 |       INDEX FAST FULL SCAN         | IDX_C_CLAIM_03          |  5527 |   161K|       |    46   (0)| 00:00:01 | DOICLC |
    |   7 |       INDEX FAST FULL SCAN         | PK_C_CLAIM              |  5527 |   161K|       |    36   (0)| 00:00:01 | DOICLC |
    |   8 |     TABLE ACCESS FULL              | C_RESERVE_LIST          |   144K|  5496K|       |   450   (2)| 00:00:06 | DOICLC |
    |   9 |    SORT AGGREGATE                  |                         |     1 |    24 |       |            |          |        |
    |  10 |     FIRST ROW                      |                         |     1 |    24 |       |     3   (0)| 00:00:01 |        |
    |* 11 |      INDEX RANGE SCAN (MIN/MAX)    | IDX_C_RESERVE_LIST_TEST |     1 |    24 |       |     3   (0)| 00:00:01 | DOICLC |
    |  12 |       SORT AGGREGATE               |                         |     1 |    21 |       |            |          |        |
    |* 13 |        INDEX RANGE SCAN            | IDX_C_RESERVE_LIST_TEST |    32 |   672 |       |     3   (0)| 00:00:01 | DOICLC |
    |  14 |       SORT AGGREGATE               |                         |     1 |    46 |       |            |          |        |
    |* 15 |        HASH JOIN                   |                         |     3 |   138 |       |     9  (12)| 00:00:01 |        |
    |  16 |         TABLE ACCESS BY INDEX ROWID| C_RESERVE_LIST          |     2 |    54 |       |     4   (0)| 00:00:01 | DOICLC |
    |* 17 |          INDEX RANGE SCAN          | IDX_C_RESERVE_LIST_TEST |     2 |       |       |     3   (0)| 00:00:01 | DOICLC |
    |  18 |         TABLE ACCESS BY INDEX ROWID| C_RESERVE_LIST          |     2 |    38 |       |     4   (0)| 00:00:01 | DOICLC |
    |* 19 |          INDEX RANGE SCAN          | IDX_C_RESERVE_LIST_TEST |     2 |       |       |     3   (0)| 00:00:01 | DOICLC |
    -------------------------------------------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       2 - filter("A2"."BUSI_PHASE"= (SELECT MAX("A4"."BUSI_PHASE") FROM "aclaim"."C_RESERVE_LIST" "A4" WHERE 
                  "A4"."CLAIM_NO"=:B1 AND "A4"."LAST_MODIFY_DATE"= (SELECT MAX("A5"."LAST_MODIFY_DATE") FROM 
                  "aclaim"."C_RESERVE_LIST" "A5" WHERE "A5"."CLAIM_NO"=:B2 AND "A5"."LAST_MODIFY_DATE"<TO_DATE(' 2017-06-26 
                  00:00:00', 'syyyy-mm-dd hh24:mi:ss'))) AND "A2"."COUNT"= (SELECT MAX("A3"."COUNT") FROM "aclaim"."C_RESERVE_LIST" 
                  "A3","aclaim"."C_RESERVE_LIST" "A6" WHERE "A6"."LAST_MODIFY_DATE"<TO_DATE(' 2017-06-26 00:00:00', 'syyyy-mm-dd 
                  hh24:mi:ss') AND "A6"."BUSI_PHASE"=:B3 AND "A6"."CLAIM_NO"=:B4 AND "A3"."BUSI_PHASE"=:B5 AND "A3"."CLAIM_NO"=:B6 AND 
                  "A3"."COUNT"="A6"."COUNT"))
       3 - access("A1"."CLAIMNO"(+)="A2"."CLAIM_NO")
       5 - access(ROWID=ROWID)
      11 - access("A4"."CLAIM_NO"=:B1)
           filter("A4"."LAST_MODIFY_DATE"= (SELECT MAX("A5"."LAST_MODIFY_DATE") FROM "aclaim"."C_RESERVE_LIST" "A5" 
                  WHERE "A5"."CLAIM_NO"=:B1 AND "A5"."LAST_MODIFY_DATE"<TO_DATE(' 2017-06-26 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))
      13 - access("A5"."CLAIM_NO"=:B1 AND "A5"."LAST_MODIFY_DATE"<TO_DATE(' 2017-06-26 00:00:00', 'syyyy-mm-dd 
                  hh24:mi:ss'))
           filter("A5"."LAST_MODIFY_DATE"<TO_DATE(' 2017-06-26 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
      15 - access("A3"."COUNT"="A6"."COUNT")
      17 - access("A6"."CLAIM_NO"=:B1 AND "A6"."BUSI_PHASE"=:B2 AND "A6"."LAST_MODIFY_DATE"<TO_DATE(' 2017-06-26 
                  00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
      19 - access("A3"."CLAIM_NO"=:B1 AND "A3"."BUSI_PHASE"=:B2)
    
    Note
    -----
       - fully remote statement
    
  • 相关阅读:
    CF 561 div2 C
    CF #560 div3
    1.11 acm结束了,所以寒假学习Java基础
    11.5 cometoj #12 -- D XOR Pair (数位dp)
    11 .3 数位dp
    10.1 叉积 ,极角排序,扫描法求凸包
    9.11 状态矩阵 与 dp
    9.3 整理一下最短路算法
    9.3 欧拉定理 && 欧拉降幂 (扩展欧拉定理)&& 指数循环节
    Two Arithmetic Progressions (exgcd的一些注意事项
  • 原文地址:https://www.cnblogs.com/wanbin/p/9514721.html
Copyright © 2011-2022 走看看