优化在具有500M行的Oracle表上运行的更新SQL

时间:2019-07-18 19:11:04

标签: oracle plsql

我正在根据前端应用程序的输入运行以下更新查询。由于它正在更新超过550M的行,因此我在执行5个小时后手动将其停止。整个代码很大,所以我在下面的代码中发布了2个字段。您能否建议可以在此方面做些什么改进?

我已经对其进行了广泛的研究,例如add pragma udf in function,但我不愿意在其中添加PRAGMA UDF,因为在PLSQL内部的生产环境中,这些函数已在数百万其他转换/计算中使用,因此我已经读过PRAGMA UDF slows down if functions are being called from PL/SQL rather than SQL

1)您能否建议我如何在不更改原始功能的情况下在此块中添加PRAGMA UDF?

2)是否应该在更新语句中为索引添加提示?如果是,如何在更新块中添加提示,例如索引提示?

P.S.: 1) Explain plan is from the test environment in which I've very few rows of data as compared to the production environment.2) other fields are using the same functions.

--EXPLAIN PLAN

Plan hash value: 234644540

---------------------------------------------------------------------------------------------------------
| Id  | Operation                               | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------------
|   0 | MERGE STATEMENT                         |               |     1 |  2527 |   240   (0)| 00:00:01 |
|   1 |  MERGE                                  | MORT_BACK_SEC |       |       |            |          |
|   2 |   VIEW                                  |               |       |       |            |          |
|   3 |    NESTED LOOPS                         |               |     1 |  2498 |   240   (0)| 00:00:01 |
|   4 |     NESTED LOOPS                        |               |   372 |  2498 |   240   (0)| 00:00:01 |
|   5 |      TABLE ACCESS BY INDEX ROWID BATCHED| RPT_ACCT_HIER |     1 |   491 |     2   (0)| 00:00:01 |
|*  6 |       INDEX RANGE SCAN                  | IDX2          |     1 |       |     1   (0)| 00:00:01 |
|*  7 |      INDEX RANGE SCAN                   | IDX4          |   372 |       |     1   (0)| 00:00:01 |
|*  8 |     TABLE ACCESS BY INDEX ROWID         | MORT_BACK_SEC |     1 |  2007 |   238   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   6 - access("RPT_ACCT_HIER"."ACCT_GEN2"='a1000')
   7 - access("D"."GL_ACCOUNT_ID"="RPT_ACCT_HIER"."ACCT_MEMBER")
   8 - filter("D"."AS_OF_DATE"=TO_DATE(' 2019-06-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)
   - automatic DOP: Computed Degree of Parallelism is 1 because of parallel threshold
   - 1 Sql Plan Directive used for this statement

-------------------------------------------------------------------------------
--CODE

IF id = 8 then
MERGE INTO(
SELECT A.*,
USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (IMP_CUR_BOOK_BAL, 0), NVL (BAS_CAP_FACTOR_K, 0), .06, .08) AS V_IMP_BAS_EB_RWA

--and 20 more function calls for 20 other fields 

FROM USB.MORT_BACK_SEC A) D

USING (SELECT * FROM USB.rpt_acct_hier) B
       ON (a.gl_account_id = b.acct_member and a.as_of_date = TO_DATE('06/30/2019','MM/DD/YYYY') and b.acct_gen2 = 'a1000')

WHEN MATCHED THEN UPDATE SET 
IMP_BAS_EB_RWA = V_IMP_BAS_EB_RWA,
IMP_BAS_EB_TOTAL_CAPITAL = ROUND (USB.BAS2_MGRL_CAPITAL (TO_DATE('06/30/2019','MM/DD/YYYY'), V_IMP_BAS_EB_RWA, 0), 2)
WHERE AS_OF_DATE = TO_DATE('06/30/2019','MM/DD/YYYY') --V_IMP_BAS_EB_RWA is being calculated above and then passed as input here

--20 more fields to be updated

end if;


--USB."BAS2_MGRL_CAPITAL" function is being called for updating IMP_BAS_EB_TOTAL_CAPITAL 

CREATE OR REPLACE FUNCTION USB."BAS2_MGRL_CAPITAL"
 (v_date in date, v_RWA in number,v_RWC in number) return number result_cache

 is

v_capital number(14,2);
v_rate number(15,8);

begin

v_rate := case when year(v_date) < 2010 then 0.06
          when year(v_date) >= 2010 and year(v_date) < 2012 then 0.07
          when year(v_date) = 2012 then 0.0775  
          when year(v_date) > 2012 and  year(v_date) < 2018 then 0.08        
else 0.085 end;


v_capital := (v_RWA + v_RWC) * v_rate;
return round(v_capital,2);

end;
/

--USB."BAS2_RWA_CALC" function which is inside MERGE into(...) block is as below


CREATE OR REPLACE FUNCTION USB."BAS2_RWA_CALC" 
(v_formula in char,v_bal in number,v_k_factor in number, v_bas_min in number,v_rwa_adj_rate in number) return number result_cache

 is

v_rwa number(15,2);

begin

v_rwa := nvl(v_bal,0)*nvl(v_k_factor,0)/nvl(v_bas_min,0);
v_rwa := v_rwa*(1+v_rwa_adj_rate);
return round(v_rwa,2);

end;
/

0 个答案:

没有答案