再一次用merge優化update
阿新 • • 發佈:2019-01-26
程式碼上線前稽核,某銀行理財系統一條update執行了一個多小時……
改寫前的SQL以及執行計劃 update fnc.t1_cust_sign_info s set s.is_wealth = (select case when ttt.total_amt >= (select sp.paravalue from fnc.sys_param sp where sp.moduleid = '5' and sp.paraid = '60000007') then '2' when ttt.total_amt < (select sp.paravalue from fnc.sys_param sp where sp.moduleid = '5' and sp.paraid = '60000007') and ttt.total_amt >= (select sp.paravalue from fnc.sys_param sp where sp.moduleid = '5' and sp.paraid = '60000006') then '0' else s.is_wealth end from (select t2.cust_no, sum(t2.app_amt) total_amt from (select /*+ index(t idx_kf2_1 )*/t.cust_no, t.app_amt * nvl(cur.standard_price, 1) app_amt from fnc.t5_cust_trans_log t left join (SELECT f2.foreign_cur,f2.standard_price FROM (SELECT f1.foreign_cur, f1.file_time, f1.standard_price, MAX(f1.file_time)over(partition BY f1.foreign_cur ) max_file_time FROM fnc.t5_foreign_cur f1) f2 WHERE f2.file_time = f2.max_file_time)cur on cur.foreign_cur = t.cur where t.busi_code in ('130', '122') and t.trans_status = '0'--測試階段改為'0',線上要改成'3' and t.cust_type = '3' union all select /*+ index(t idx_kf2_2 )*/t.cust_no, t.total_vol * nvl(p.nav, 1) * nvl(cur.standard_price, 1) app_amt from fnc.t5_cust_vol t --與表t1_cust_info關聯列 cust_no需要建立索引 left join fnc.t5_prod_info p on p.prod_code = t.prod_code left join (SELECT f2.foreign_cur,f2.standard_price FROM (SELECT f1.foreign_cur, f1.file_time, f1.standard_price, MAX(f1.file_time)over(partition BY f1.foreign_cur ) max_file_time FROM fnc.t5_foreign_cur f1) f2 WHERE f2.file_time = f2.max_file_time)cur on cur.foreign_cur = p.prod_currency left join fnc.t1_cust_info c on c.cust_no = t.cust_no where c.cust_type = '3') t2 group by t2.cust_no) ttt where ttt.cust_no = s.cust_no) where exists (select 1 from (select t.cust_no, t.app_amt from fnc.t5_cust_trans_log t where t.busi_code in ('130', '122') and t.trans_status = '0'--測試階段改為'0',線上要改成'3' and t.cust_type = '3') t2 where t2.cust_no = s.cust_no); PLAN_TABLE_OUTPUT ---------------------------------------------------------------------------------------------------------------- Plan hash value: 2887642830 --------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------------------------- | 0 | UPDATE STATEMENT | | 4252 | 116K| 27M (1)| 91:17:25 | | 1 | UPDATE | T1_CUST_SIGN_INFO | | | | | |* 2 | HASH JOIN RIGHT SEMI | | 4252 | 116K| 4185 (1)| 00:00:51 | | 3 | INLIST ITERATOR | | | | | | |* 4 | TABLE ACCESS BY INDEX ROWID | T5_CUST_TRANS_LOG | 2962 | 50354 | 2882 (1)| 00:00:35 | |* 5 | INDEX RANGE SCAN | IX_T5_CUST_TRANS_LOG_02 | 3543 | | 68 (0)| 00:00:01 | | 6 | TABLE ACCESS FULL | T1_CUST_SIGN_INFO | 1337K| 14M| 1296 (2)| 00:00:16 | | 7 | VIEW | | 2 | 46 | 6439 (1)| 00:01:18 | | 8 | SORT GROUP BY | | 2 | 44 | 6439 (1)| 00:01:18 | | 9 | VIEW | | 768 | 16896 | 6439 (1)| 00:01:18 | | 10 | UNION-ALL | | | | | | |* 11 | HASH JOIN OUTER | | 388 | 30264 | 2987 (1)| 00:00:36 | | 12 | INLIST ITERATOR | | | | | | |* 13 | TABLE ACCESS BY INDEX ROWID | T5_CUST_TRANS_LOG | 1 | 25 | 2882 (1)| 00:00:35 | |* 14 | INDEX RANGE SCAN | IX_T5_CUST_TRANS_LOG_02 | 3543 | | 68 (0)| 00:00:01 | |* 15 | VIEW | | 9952 | 515K| 105 (2)| 00:00:02 | | 16 | WINDOW SORT | | 9952 | 281K| 105 (2)| 00:00:02 | | 17 | TABLE ACCESS FULL | T5_FOREIGN_CUR | 9952 | 281K| 103 (0)| 00:00:02 | |* 18 | HASH JOIN OUTER | | 380 | 42940 | 3452 (1)| 00:00:42 | | 19 | NESTED LOOPS OUTER | | 1 | 60 | 3347 (1)| 00:00:41 | | 20 | NESTED LOOPS | | 1 | 38 | 3345 (1)| 00:00:41 | |* 21 | TABLE ACCESS BY INDEX ROWID| T1_CUST_INFO | 1 | 11 | 3 (0)| 00:00:01 | |* 22 | INDEX UNIQUE SCAN | PK_T1_CUST_INFO | 1 | | 2 (0)| 00:00:01 | |* 23 | TABLE ACCESS FULL | T5_CUST_VOL | 1 | 27 | 3342 (1)| 00:00:41 | | 24 | TABLE ACCESS BY INDEX ROWID | T5_PROD_INFO | 1 | 22 | 2 (0)| 00:00:01 | |* 25 | INDEX RANGE SCAN | PK_T5_PROD_INFO | 1 | | 1 (0)| 00:00:01 | |* 26 | VIEW | | 9952 | 515K| 105 (2)| 00:00:02 | | 27 | WINDOW SORT | | 9952 | 281K| 105 (2)| 00:00:02 | | 28 | TABLE ACCESS FULL | T5_FOREIGN_CUR | 9952 | 281K| 103 (0)| 00:00:02 | | 29 | TABLE ACCESS BY INDEX ROWID | SYS_PARAM | 1 | 15 | 1 (0)| 00:00:01 | |* 30 | INDEX UNIQUE SCAN | PK_SYS_PARAM | 1 | | 0 (0)| 00:00:01 | | 31 | TABLE ACCESS BY INDEX ROWID | SYS_PARAM | 1 | 15 | 1 (0)| 00:00:01 | |* 32 | INDEX UNIQUE SCAN | PK_SYS_PARAM | 1 | | 0 (0)| 00:00:01 | | 33 | TABLE ACCESS BY INDEX ROWID | SYS_PARAM | 1 | 15 | 1 (0)| 00:00:01 | |* 34 | INDEX UNIQUE SCAN | PK_SYS_PARAM | 1 | | 0 (0)| 00:00:01 | --------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("T"."CUST_NO"="S"."CUST_NO") 4 - filter("T"."CUST_NO" IS NOT NULL AND "T"."CUST_TYPE"='3') 5 - access(("T"."BUSI_CODE"='122' OR "T"."BUSI_CODE"='130') AND "T"."TRANS_STATUS"='0') 11 - access("F2"."FOREIGN_CUR"(+)="T"."CUR") 13 - filter("T"."CUST_NO"=:B1 AND "T"."CUST_TYPE"='3') 14 - access(("T"."BUSI_CODE"='122' OR "T"."BUSI_CODE"='130') AND "T"."TRANS_STATUS"='0') 15 - filter("F2"."FILE_TIME"(+)="F2"."MAX_FILE_TIME"(+)) 18 - access("F2"."FOREIGN_CUR"(+)="P"."PROD_CURRENCY") 21 - filter("C"."CUST_TYPE"='3') 22 - access("C"."CUST_NO"=:B1) 23 - filter("T"."CUST_NO"=:B1 AND "C"."CUST_NO"="T"."CUST_NO") 25 - access("P"."PROD_CODE"(+)="T"."PROD_CODE") 26 - filter("F2"."FILE_TIME"(+)="F2"."MAX_FILE_TIME"(+)) 30 - access("SP"."PARAID"='60000007' AND "SP"."MODULEID"='5') 32 - access("SP"."PARAID"='60000007' AND "SP"."MODULEID"='5') 34 - access("SP"."PARAID"='60000006' AND "SP"."MODULEID"='5')
OWNER OBJECT_TYPE OBJECT_NAME ALIAS PAR SIZE_MB NUM_ROWS ESTIMATE_P LAST_ANALYZE STA ---------- -------------------- ------------------------------ ---------------------------------------- --- ---------- ---------- ---------- ------------ --- FNC TABLE SYS_PARAM SP | SP | SP NO .0625 77 100% 30-SEP-16 NO FNC TABLE T1_CUST_INFO C NO 299 1297140 100% 19-JUL-16 NO FNC TABLE T1_CUST_SIGN_INFO C | S NO 37 1337492 100% 30-SEP-16 NO FNC TABLE T5_CUST_TRANS_LOG T | T NO 216 6342 100% 30-SEP-16 YES FNC TABLE T5_CUST_VOL T NO 96 528534 100% 30-SEP-16 NO FNC TABLE T5_FOREIGN_CUR F1 | F1 NO 3 9952 100% 09-SEP-16 NO FNC TABLE T5_PROD_INFO P NO 5 14497 100% 30-SEP-16 NO FNC INDEX IX_T5_CUST_TRANS_LOG_02 NOALIAS | NOALIAS NO 28 6345 100% 30-SEP-16 YES FNC INDEX (UNIQUE) PK_SYS_PARAM NOALIAS | NOALIAS | NOALIAS NO .0625 77 100% 30-SEP-16 NO SQL> SELECT COUNT(1) FROM T5_CUST_TRANS_LOG; COUNT(1) ---------- 7511
改寫後的SQL以及執行計劃 merge into t1_cust_sign_info c using (select distinct a.rid,a.cust_no, case when b.total_amt >= (select sp.paravalue from sys_param sp where sp.moduleid = '5' and sp.paraid = '60000007') then '2' when b.total_amt < (select sp.paravalue from sys_param sp where sp.moduleid = '5' and sp.paraid = '60000007') and b.total_amt >= (select sp.paravalue from sys_param sp where sp.moduleid = '5' and sp.paraid = '60000006') then '0' else a.is_wealth end as is_wealth from ( select s.rowid rid, s.cust_no,s.is_wealth from t1_cust_sign_info s, t5_cust_trans_log t where s.cust_no = t.cust_no and t.busi_code in ('130', '122') and t.trans_status = '0'--測試階段改為'0',線上要改成'3' and t.cust_type = '3') a left join (select t2.cust_no, sum(t2.app_amt) total_amt from (select t.cust_no, t.app_amt * nvl(cur.standard_price, 1) app_amt from t5_cust_trans_log t left join (SELECT f2.foreign_cur,f2.standard_price FROM (SELECT f1.foreign_cur, f1.file_time, f1.standard_price, MAX(f1.file_time)over(partition BY f1.foreign_cur ) max_file_time FROM t5_foreign_cur f1) f2 WHERE f2.file_time = f2.max_file_time)cur on cur.foreign_cur = t.cur where t.busi_code in ('130', '122') and t.trans_status = '0'--測試階段改為'0',線上要改成'3' and t.cust_type = '3' union all select t.cust_no, t.total_vol * nvl(p.nav, 1) * nvl(cur.standard_price, 1) app_amt from t5_cust_vol t --與表t1_cust_info關聯列 cust_no需要建立索引 left join t5_prod_info p on p.prod_code = t.prod_code left join (SELECT f2.foreign_cur,f2.standard_price FROM (SELECT f1.foreign_cur, f1.file_time, f1.standard_price, MAX(f1.file_time)over(partition BY f1.foreign_cur ) max_file_time FROM t5_foreign_cur f1) f2 WHERE f2.file_time = f2.max_file_time)cur on cur.foreign_cur = p.prod_currency left join t1_cust_info c on c.cust_no = t.cust_no where c.cust_type = '3') t2 group by t2.cust_no) b on a.cust_no = b.cust_no ) d on(d.rid = c.rowid) when matched then update set c.is_wealth = d.is_wealth; 4570 rows merged. Elapsed: 00:00:05.40 PLAN_TABLE_OUTPUT ----------------------------------------------------------------------------------------------------------- Plan hash value: 966278225 --------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | --------------------------------------------------------------------------------------------------------------------------- | 0 | MERGE STATEMENT | | 2962 | 11848 | | 33791 (2)| 00:06:46 | | 1 | MERGE | T1_CUST_SIGN_INFO | | | | | | | 2 | TABLE ACCESS BY INDEX ROWID | SYS_PARAM | 1 | 15 | | 1 (0)| 00:00:01 | |* 3 | INDEX UNIQUE SCAN | PK_SYS_PARAM | 1 | | | 0 (0)| 00:00:01 | | 4 | TABLE ACCESS BY INDEX ROWID | SYS_PARAM | 1 | 15 | | 1 (0)| 00:00:01 | |* 5 | INDEX UNIQUE SCAN | PK_SYS_PARAM | 1 | | | 0 (0)| 00:00:01 | | 6 | TABLE ACCESS BY INDEX ROWID | SYS_PARAM | 1 | 15 | | 1 (0)| 00:00:01 | |* 7 | INDEX UNIQUE SCAN | PK_SYS_PARAM | 1 | | | 0 (0)| 00:00:01 | | 8 | VIEW | | | | | | | |* 9 | HASH JOIN | | 2962 | 118K| | 33791 (2)| 00:06:46 | | 10 | VIEW | | 2962 | 62202 | | 32484 (1)| 00:06:30 | | 11 | SORT UNIQUE | | 2962 | 170K| | 32484 (1)| 00:06:30 | |* 12 | HASH JOIN OUTER | | 2962 | 170K| | 32483 (1)| 00:06:30 | |* 13 | HASH JOIN | | 2962 | 107K| | 4185 (1)| 00:00:51 | | 14 | INLIST ITERATOR | | | | | | | |* 15 | TABLE ACCESS BY INDEX ROWID | T5_CUST_TRANS_LOG | 2962 | 50354 | | 2882 (1)| 00:00:35 | |* 16 | INDEX RANGE SCAN | IX_T5_CUST_TRANS_LOG_02 | 3543 | | | 68 (0)| 00:00:01 | | 17 | TABLE ACCESS FULL | T1_CUST_SIGN_INFO | 1337K| 25M| | 1296 (2)| 00:00:16 | | 18 | VIEW | | 344K| 7397K| | 28295 (2)| 00:05:40 | | 19 | SORT GROUP BY | | 344K| 7397K| 95M| 28295 (2)| 00:05:40 | | 20 | VIEW | | 3104K| 65M| | 19434 (1)| 00:03:54 | | 21 | UNION-ALL | | | | | | | |* 22 | HASH JOIN OUTER | | 1650K| 122M| | 2996 (1)| 00:00:36 | | 23 | INLIST ITERATOR | | | | | | | |* 24 | TABLE ACCESS BY INDEX ROWID| T5_CUST_TRANS_LOG | 3348 | 83700 | | 2882 (1)| 00:00:35 | |* 25 | INDEX RANGE SCAN | IX_T5_CUST_TRANS_LOG_02 | 3543 | | | 68 (0)| 00:00:01 | |* 26 | VIEW | | 9952 | 515K| | 105 (2)| 00:00:02 | | 27 | WINDOW SORT | | 9952 | 281K| | 105 (2)| 00:00:02 | | 28 | TABLE ACCESS FULL | T5_FOREIGN_CUR | 9952 | 281K| | 103 (0)| 00:00:02 | |* 29 | HASH JOIN RIGHT OUTER | | 1453K| 156M| | 16438 (1)| 00:03:18 | |* 30 | VIEW | | 9952 | 515K| | 105 (2)| 00:00:02 | | 31 | WINDOW SORT | | 9952 | 281K| | 105 (2)| 00:00:02 | | 32 | TABLE ACCESS FULL | T5_FOREIGN_CUR | 9952 | 281K| | 103 (0)| 00:00:02 | |* 33 | HASH JOIN RIGHT OUTER | | 528K| 30M| | 16325 (1)| 00:03:16 | | 34 | TABLE ACCESS FULL | T5_PROD_INFO | 14497 | 311K| | 175 (1)| 00:00:03 | |* 35 | HASH JOIN | | 528K| 19M| 19M| 16147 (1)| 00:03:14 | | 36 | TABLE ACCESS FULL | T5_CUST_VOL | 528K| 13M| | 3341 (1)| 00:00:41 | |* 37 | TABLE ACCESS FULL | T1_CUST_INFO | 1293K| 13M| | 10404 (1)| 00:02:05 | | 38 | TABLE ACCESS FULL | T1_CUST_SIGN_INFO | 1337K| 25M| | 1299 (2)| 00:00:16 | --------------------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("SP"."PARAID"='60000007' AND "SP"."MODULEID"='5') 5 - access("SP"."PARAID"='60000007' AND "SP"."MODULEID"='5') 7 - access("SP"."PARAID"='60000006' AND "SP"."MODULEID"='5') 9 - access("D"."RID"="C".ROWID) 12 - access("S"."CUST_NO"="B"."CUST_NO"(+)) 13 - access("S"."CUST_NO"="T"."CUST_NO") 15 - filter("T"."CUST_NO" IS NOT NULL AND "T"."CUST_TYPE"='3') 16 - access(("T"."BUSI_CODE"='122' OR "T"."BUSI_CODE"='130') AND "T"."TRANS_STATUS"='0') 22 - access("F2"."FOREIGN_CUR"(+)="T"."CUR") 24 - filter("T"."CUST_TYPE"='3') 25 - access(("T"."BUSI_CODE"='122' OR "T"."BUSI_CODE"='130') AND "T"."TRANS_STATUS"='0') 26 - filter("F2"."FILE_TIME"(+)="F2"."MAX_FILE_TIME"(+)) 29 - access("F2"."FOREIGN_CUR"(+)="P"."PROD_CURRENCY") 30 - filter("F2"."FILE_TIME"(+)="F2"."MAX_FILE_TIME"(+)) 33 - access("P"."PROD_CODE"(+)="T"."PROD_CODE") 35 - access("C"."CUST_NO"="T"."CUST_NO") 37 - filter("C"."CUST_TYPE"='3') 66 rows selected.
優化後 5秒執行完 而原來執行一個小時都不出結果!!!