我正在根据前端应用程序的输入运行以下更新查询。由于它正在更新超过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;
/