DBLINK引起的SQL性能问题
2017-11-30 11:20
537 查看
最近发现报表系统上有一存储过程越来越慢,在数据库中查询后,发现有以下条SQL
执行SQL,10s内能返回全部结果。
但是,在报表库上运行时,发现SQL的性能还是没改善。
再次分析执行计划:
发现此sql运行时,采用多个dblink访问远程库。查看dblink的元数据:
发现两个DBLINK都是访问AUTOCLAIM用户下的表。
这种方式很容易造成sql不能走正确执行计划,所以可以把sql中的dblink改写成同一个。
再次执行,10s内能返回全部结果。
--优化前:耗时>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
相关文章推荐
- DBLINK引起的SQL性能问题
- SQL嵌套查询引起的性能问题分析
- sql语句中的字段类型与sql表字段类型不一致可能引起的性能问题
- SQL优化技巧--远程连接对象引起的CTE性能问题
- 记一次处理oracle分区表索引"乱用"引起的SQL性能问题
- 性能测试中SQL引起的性能问题
- Oracle 静态SQL引起性能问题
- 【多线程同步案例】Race Condition引起的性能问题
- mysql通过将or改成union来优化sql性能问题一例
- SQL性能突然降低引起的业务办理缓慢案例一则
- java使用"+"拼装sql和hql引起的效率问题
- SQL 更新数据时触发器造成的性能问题
- 自动装箱拆箱在Java集合类框架引起的性能问题
- SQL Server 中VARCHAR(MAX)变量赋值引起的性能问题。
- 大量并发SQL导致数据库性能问题诊断优化
- 关联查询中使用TOP引起的性能问题分析
- ASP中SQL语句导致的性能问题
- 2017-05-22 dba日记,使用add_months函数解决现实SQL性能问题
- 自定义函数导致的sql性能问题
- sql 查询性能的问题 有order by 和无order by 速度竟然相差百倍