我在 Web 项目中使用的更新 PL/SQL 块内部程序花费的时间太长

Update PL/SQL block inside procedure, which I'm using in web project, is taking too long

我已经编写了 PL/SQL 代码来更新 table 的列,基于从前端应用程序传递的输入,例如如果 INSTTABLE = 8 那么接下来的块将 运行。我有 90 多个这样的应用程序和 运行ning 更新 procedure.During 在 dev environment 中测试它,尽管代码工作正常并且正在执行预期的工作,即先将列值设置为零,然后然后调用几个函数做财务计算,时间太长(一个多小时)。最初我认为这是因为数百万 rows/data 但我在这里发布它是为了检查代码是否可以进一步改进以减少执行时间。

在此先感谢您的帮助!

PS:我无法更改函数,例如 BAS2_RWA_CALC 内部 calc/return 值,因为它被产品中的许多其他过程使用,因此我设置了在进行主更新之前,在单独的更新语句中将列设置为 0。将其设置为零的原因是生产遵循相同的逻辑,即先将列设置为 0,然后再进行计算。如果我不这样做,对比查询就会有差异。

--explain plan for update set values to zero
------------------------------------------------------------------------------------
| Id  | Operation          | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT   |               | 25545 |  4365K|  1383   (1)| 00:00:01 |
|   1 |  UPDATE            | MORT_BACK_SEC |       |       |            |          |
|*  2 |   TABLE ACCESS FULL| MORT_BACK_SEC | 25545 |  4365K|  1383   (1)| 00:00:01 |
------------------------------------------------------------------------------------

--Explain plan for merge
--------------------------------------------------------------------------------------
| Id  | Operation            | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | MERGE STATEMENT      |               |     1 |  2605 |  1541   (1)| 00:00:01 |
|   1 |  MERGE               | MORT_BACK_SEC |       |       |            |          |
|   2 |   VIEW               |               |       |       |            |          |
|*  3 |    HASH JOIN         |               |     1 |  2498 |  1541   (1)| 00:00:01 |
|*  4 |     TABLE ACCESS FULL| RPT_ACCT_HIER |     1 |   491 |   156   (0)| 00:00:01 |
|*  5 |     TABLE ACCESS FULL| MORT_BACK_SEC | 25545 |    48M|  1384   (1)| 00:00:01 |
--------------------------------------------------------------------------------------

IF INSTTABLE = 8 THEN 

--Block to set columns to zero value

  UPDATE usb.MORT_BACK_SEC SET
        BAS_EB_RWA = 0, BAS_AB_RWA = 0, BAS_EB_RWA_COMMT = 0, BAS_AB_RWA_COMMT = 0, IMP_BAS_EB_RWA = 0, IMP_BAS_AB_RWA = 0, IDS_BAS_EB_RWA = 0, 
        IDS_BAS_AB_RWA = 0, DIS_BAS_EB_RWA = 0, DIS_BAS_AB_RWA = 0, PRE_BAS_EB_RWA = 0, PRE_BAS_AB_RWA = 0, BAS_AIR_EB_RWA = 0, BAS_AIR_AB_RWA = 0, 
        BAS_DELAY_REC_EB_RWA = 0, BAS_DELAY_REC_AB_RWA = 0, BAS_TPR_EB_RWA = 0, BAS_TPR_AB_RWA = 0, BAS_UNR_EB_RWA = 0, BAS_UNR_AB_RWA = 0, 
        BAS_ICAAP_EB_RWA = 0, BAS_ICAAP_AIR_EB_RWA = 0, BAS_ICAAP_DELAY_REC_EB_RWA = 0, BAS_ICAAP_DIS_EB_RWA = 0, BAS_ICAAP_IDS_EB_RWA = 0, 
        BAS_ICAAP_IMP_EB_RWA = 0, BAS_ICAAP_PRE_EB_RWA = 0, BAS_ICAAP_TPR_EB_RWA = 0, BAS_ICAAP_UNR_EB_RWA = 0, IMP_BAS_EB_TOTAL_CAPITAL = 0, 
        IMP_BAS_AB_TOTAL_CAPITAL = 0, IDS_BAS_EB_TOTAL_CAPITAL = 0, IDS_BAS_AB_TOTAL_CAPITAL = 0, DIS_BAS_EB_TOTAL_CAPITAL = 0, DIS_BAS_AB_TOTAL_CAPITAL = 0, 
        PRE_BAS_EB_TOTAL_CAPITAL = 0, PRE_BAS_AB_TOTAL_CAPITAL = 0, BAS_AIR_EB_TOTAL_CAPITAL = 0, BAS_AIR_AB_TOTAL_CAPITAL = 0, 
        BAS_DELAY_REC_EB_TOTAL_CAPITAL = 0, BAS_DELAY_REC_AB_TOTAL_CAPITAL = 0, BAS_TPR_EB_TOTAL_CAPITAL = 0, BAS_TPR_AB_TOTAL_CAPITAL = 0, 
        BAS_UNR_EB_TOTAL_CAPITAL = 0, BAS_UNR_AB_TOTAL_CAPITAL = 0, IMP_BAS_EB_EXPECTED_LOSS = 0, IMP_BAS_AB_EXPECTED_LOSS = 0, IDS_BAS_EB_EXPECTED_LOSS = 0, 
        IDS_BAS_AB_EXPECTED_LOSS = 0, DIS_BAS_EB_EXPECTED_LOSS = 0, DIS_BAS_AB_EXPECTED_LOSS = 0, PRE_BAS_EB_EXPECTED_LOSS = 0, PRE_BAS_AB_EXPECTED_LOSS = 0, 
        BAS_AIR_EB_EXPECTED_LOSS = 0, BAS_AIR_AB_EXPECTED_LOSS = 0, BAS_DELAY_REC_EB_EXPECTED_LOSS = 0, BAS_DELAY_REC_AB_EXPECTED_LOSS = 0, 
        BAS_TPR_EB_EXPECTED_LOSS = 0, BAS_TPR_AB_EXPECTED_LOSS = 0, BAS_UNR_EB_EXPECTED_LOSS = 0, BAS_UNR_AB_EXPECTED_LOSS = 0
    WHERE AS_OF_DATE = TO_DATE('06/30/2019','MM/DD/YYYY');

    COMMIT;

   MERGE INTO ( SELECT /*+ index(a idx1) */ D.*,
       CASE WHEN GL_ACCOUNT_ID IN (1370050, 1450035) THEN 0 
       ELSE USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (CUR_BOOK_BAL, 0), NVL (BAS_CAP_FACTOR_K, 0), 0.06, 0.08) END AS V_BAS_EB_RWA,
       CASE WHEN GL_ACCOUNT_ID IN (1370050, 1450035) THEN 0 
       ELSE USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (AVG_BOOK_BAL, 0), NVL (BAS_CAP_FACTOR_K, 0), 0.06, 0.08) END AS V_BAS_AB_RWA,
       0 AS V_BAS_EB_RWA_COMMT,
       0 AS V_BAS_AB_RWA_COMMT,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (IMP_CUR_BOOK_BAL, 0), NVL (BAS_CAP_FACTOR_K, 0), 0.06, 0.08) AS V_IMP_BAS_EB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (IMP_AVG_BOOK_BAL, 0), NVL (BAS_CAP_FACTOR_K, 0), 0.06, 0.08) AS V_IMP_BAS_AB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (IDS_CUR_BOOK_BAL, 0), NVL (BAS_CAP_FACTOR_K, 0), 0.06, 0.08) AS V_IDS_BAS_EB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (IDS_AVG_BOOK_BAL, 0), NVL (BAS_CAP_FACTOR_K, 0), 0.06, 0.08) AS V_IDS_BAS_AB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (DIS_CUR_BOOK_BAL, 0), NVL (BAS_CAP_FACTOR_K, 0), 0.06, 0.08) AS V_DIS_BAS_EB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (DIS_AVG_BOOK_BAL, 0), NVL (BAS_CAP_FACTOR_K, 0), 0.06, 0.08) AS V_DIS_BAS_AB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (PRE_CUR_BOOK_BAL, 0), NVL (BAS_CAP_FACTOR_K, 0), 0.06, 0.08) AS V_PRE_BAS_EB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (PRE_AVG_BOOK_BAL, 0), NVL (BAS_CAP_FACTOR_K, 0), 0.06, 0.08) AS V_PRE_BAS_AB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (AIR_CUR_BOOK_BAL, 0), NVL (BAS_CAP_FACTOR_K, 0), 0.06, 0.08) AS V_BAS_AIR_EB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (AIR_AVG_BOOK_BAL, 0), NVL (BAS_CAP_FACTOR_K, 0), 0.06, 0.08) AS V_BAS_AIR_AB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (DELAY_REC_CUR_BOOK_BAL, 0), NVL (BAS_CAP_FACTOR_K, 0), 0.06, 0.08) AS V_BAS_DELAY_REC_EB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (DELAY_REC_AVG_BOOK_BAL, 0), NVL (BAS_CAP_FACTOR_K, 0), 0.06, 0.08) AS V_BAS_DELAY_REC_AB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (TPR_CUR_BOOK_BAL, 0), NVL (BAS_CAP_FACTOR_K, 0), 0.06, 0.08) AS V_BAS_TPR_EB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (TPR_AVG_BOOK_BAL, 0), NVL (BAS_CAP_FACTOR_K, 0), 0.06, 0.08) AS V_BAS_TPR_AB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (UNR_CUR_BOOK_BAL, 0), NVL (BAS_CAP_FACTOR_K, 0), 0.06, 0.08) AS V_BAS_UNR_EB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (UNR_AVG_BOOK_BAL, 0), NVL (BAS_CAP_FACTOR_K, 0), 0.06, 0.08) AS V_BAS_UNR_AB_RWA,
       CASE WHEN GL_ACCOUNT_ID IN (1370050, 1450035) THEN 0 
       ELSE USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (CUR_BOOK_BAL, 0), NVL (BAS_ICAAP_FACTOR_K, 0), 0.06, 0.08) END AS V_BAS_ICAAP_EB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (AIR_CUR_BOOK_BAL, 0), NVL (BAS_ICAAP_FACTOR_K, 0), 0.06, 0.08) AS V_BAS_ICAAP_AIR_EB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (DELAY_REC_CUR_BOOK_BAL, 0), NVL (BAS_ICAAP_FACTOR_K, 0), 0.06, 0.08) AS V_BAS_ICAAP_DELAY_REC_EB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (DIS_CUR_BOOK_BAL, 0), NVL (BAS_ICAAP_FACTOR_K, 0), 0.06, 0.08) AS V_BAS_ICAAP_DIS_EB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (IDS_CUR_BOOK_BAL, 0), NVL (BAS_ICAAP_FACTOR_K, 0), 0.06, 0.08) AS V_BAS_ICAAP_IDS_EB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (IMP_CUR_BOOK_BAL, 0), NVL (BAS_ICAAP_FACTOR_K, 0), 0.06, 0.08) AS V_BAS_ICAAP_IMP_EB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (PRE_CUR_BOOK_BAL, 0), NVL (BAS_ICAAP_FACTOR_K, 0), 0.06, 0.08) AS V_BAS_ICAAP_PRE_EB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (TPR_CUR_BOOK_BAL, 0), NVL (BAS_ICAAP_FACTOR_K, 0), 0.06, 0.08) AS V_BAS_ICAAP_TPR_EB_RWA,
       USB.BAS2_RWA_CALC (BAS_CAPITAL_CALC_CD, NVL (UNR_CUR_BOOK_BAL, 0), NVL (BAS_ICAAP_FACTOR_K, 0), 0.06, 0.08) AS V_BAS_ICAAP_UNR_EB_RWA
           FROM USB.MORT_BACK_SEC D ) A
   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 
       BAS_EB_RWA = V_BAS_EB_RWA,
       BAS_AB_RWA = V_BAS_AB_RWA,
       BAS_EB_RWA_COMMT = V_BAS_EB_RWA_COMMT,
       BAS_AB_RWA_COMMT = V_BAS_AB_RWA_COMMT,
       IMP_BAS_EB_RWA = V_IMP_BAS_EB_RWA,
       IMP_BAS_AB_RWA = V_IMP_BAS_AB_RWA,
       IDS_BAS_EB_RWA = V_IDS_BAS_EB_RWA,
       IDS_BAS_AB_RWA = V_IDS_BAS_AB_RWA,
       DIS_BAS_EB_RWA = V_DIS_BAS_EB_RWA,
       DIS_BAS_AB_RWA = V_DIS_BAS_AB_RWA,
       PRE_BAS_EB_RWA = V_PRE_BAS_EB_RWA,
       PRE_BAS_AB_RWA = V_PRE_BAS_AB_RWA,
       BAS_AIR_EB_RWA = V_BAS_AIR_EB_RWA,
       BAS_AIR_AB_RWA = V_BAS_AIR_AB_RWA,
       BAS_DELAY_REC_EB_RWA = V_BAS_DELAY_REC_EB_RWA,
       BAS_DELAY_REC_AB_RWA = V_BAS_DELAY_REC_AB_RWA,
       BAS_TPR_EB_RWA = V_BAS_TPR_EB_RWA,
       BAS_TPR_AB_RWA = V_BAS_TPR_AB_RWA,
       BAS_UNR_EB_RWA = V_BAS_UNR_EB_RWA,
       BAS_UNR_AB_RWA = V_BAS_UNR_AB_RWA,
       BAS_ICAAP_EB_RWA = V_BAS_ICAAP_EB_RWA,
       BAS_ICAAP_AIR_EB_RWA = V_BAS_ICAAP_AIR_EB_RWA,
       BAS_ICAAP_DELAY_REC_EB_RWA = V_BAS_ICAAP_DELAY_REC_EB_RWA,
       BAS_ICAAP_DIS_EB_RWA = V_BAS_ICAAP_DIS_EB_RWA,
       BAS_ICAAP_IDS_EB_RWA = V_BAS_ICAAP_IDS_EB_RWA,
       BAS_ICAAP_IMP_EB_RWA = V_BAS_ICAAP_IMP_EB_RWA,
       BAS_ICAAP_PRE_EB_RWA = V_BAS_ICAAP_PRE_EB_RWA,
       BAS_ICAAP_TPR_EB_RWA = V_BAS_ICAAP_TPR_EB_RWA,
       BAS_ICAAP_UNR_EB_RWA = V_BAS_ICAAP_UNR_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),
       IMP_BAS_AB_TOTAL_CAPITAL = ROUND (USB.BAS2_MGRL_CAPITAL (TO_DATE('06/30/2019','MM/DD/YYYY'), V_IMP_BAS_AB_RWA, 0), 2),
       IDS_BAS_EB_TOTAL_CAPITAL = ROUND (USB.BAS2_MGRL_CAPITAL (TO_DATE('06/30/2019','MM/DD/YYYY'), V_IDS_BAS_EB_RWA, 0), 2),
       IDS_BAS_AB_TOTAL_CAPITAL = ROUND (USB.BAS2_MGRL_CAPITAL (TO_DATE('06/30/2019','MM/DD/YYYY'), V_IDS_BAS_AB_RWA, 0), 2),
       DIS_BAS_EB_TOTAL_CAPITAL = ROUND (USB.BAS2_MGRL_CAPITAL (TO_DATE('06/30/2019','MM/DD/YYYY'), V_DIS_BAS_EB_RWA, 0), 2),
       DIS_BAS_AB_TOTAL_CAPITAL = ROUND (USB.BAS2_MGRL_CAPITAL (TO_DATE('06/30/2019','MM/DD/YYYY'), V_DIS_BAS_AB_RWA, 0), 2),
       PRE_BAS_EB_TOTAL_CAPITAL = ROUND (USB.BAS2_MGRL_CAPITAL (TO_DATE('06/30/2019','MM/DD/YYYY'), V_PRE_BAS_EB_RWA, 0), 2),
       PRE_BAS_AB_TOTAL_CAPITAL = ROUND (USB.BAS2_MGRL_CAPITAL (TO_DATE('06/30/2019','MM/DD/YYYY'), V_PRE_BAS_AB_RWA, 0), 2),
       BAS_AIR_EB_TOTAL_CAPITAL = ROUND (USB.BAS2_MGRL_CAPITAL (TO_DATE('06/30/2019','MM/DD/YYYY'), V_BAS_AIR_EB_RWA, 0), 2),
       BAS_AIR_AB_TOTAL_CAPITAL = ROUND (USB.BAS2_MGRL_CAPITAL (TO_DATE('06/30/2019','MM/DD/YYYY'), V_BAS_AIR_AB_RWA, 0), 2),
       BAS_DELAY_REC_EB_TOTAL_CAPITAL = ROUND (USB.BAS2_MGRL_CAPITAL (TO_DATE('06/30/2019','MM/DD/YYYY'), V_BAS_DELAY_REC_EB_RWA, 0), 2),
       BAS_DELAY_REC_AB_TOTAL_CAPITAL = ROUND (USB.BAS2_MGRL_CAPITAL (TO_DATE('06/30/2019','MM/DD/YYYY'), V_BAS_DELAY_REC_AB_RWA, 0), 2),

       BAS_TPR_EB_TOTAL_CAPITAL = ROUND (USB.BAS2_MGRL_CAPITAL (TO_DATE('06/30/2019','MM/DD/YYYY'), V_BAS_TPR_EB_RWA, 0), 2),
       BAS_TPR_AB_TOTAL_CAPITAL = ROUND (USB.BAS2_MGRL_CAPITAL (TO_DATE('06/30/2019','MM/DD/YYYY'), V_BAS_TPR_AB_RWA, 0), 2),
       BAS_UNR_EB_TOTAL_CAPITAL = ROUND (USB.BAS2_MGRL_CAPITAL (TO_DATE('06/30/2019','MM/DD/YYYY'), V_BAS_UNR_EB_RWA, 0), 2),
       BAS_UNR_AB_TOTAL_CAPITAL = ROUND (USB.BAS2_MGRL_CAPITAL (TO_DATE('06/30/2019','MM/DD/YYYY'), V_BAS_UNR_AB_RWA, 0), 2),
       -- CALCULATE BAS_EB_EXPECTED_LOSS AND  BAS_AB_EXPECTED_LOSS
       IMP_BAS_EB_EXPECTED_LOSS = USB.BAS2_EL_CALC (IMP_CUR_BOOK_BAL, 0, BAS_PD, BAS_LGD, 0),
       IMP_BAS_AB_EXPECTED_LOSS = USB.BAS2_EL_CALC (IMP_AVG_BOOK_BAL, 0, BAS_PD, BAS_LGD, 0),
       IDS_BAS_EB_EXPECTED_LOSS = USB.BAS2_EL_CALC (IDS_CUR_BOOK_BAL, 0, BAS_PD, BAS_LGD, 0),
       IDS_BAS_AB_EXPECTED_LOSS = USB.BAS2_EL_CALC (IDS_AVG_BOOK_BAL, 0, BAS_PD, BAS_LGD, 0),
       DIS_BAS_EB_EXPECTED_LOSS = USB.BAS2_EL_CALC (DIS_CUR_BOOK_BAL, 0, BAS_PD, BAS_LGD, 0),
       DIS_BAS_AB_EXPECTED_LOSS = USB.BAS2_EL_CALC (DIS_AVG_BOOK_BAL, 0, BAS_PD, BAS_LGD, 0),
       PRE_BAS_EB_EXPECTED_LOSS = USB.BAS2_EL_CALC (PRE_CUR_BOOK_BAL, 0, BAS_PD, BAS_LGD, 0),
       PRE_BAS_AB_EXPECTED_LOSS = USB.BAS2_EL_CALC (PRE_AVG_BOOK_BAL, 0, BAS_PD, BAS_LGD, 0),
       BAS_AIR_EB_EXPECTED_LOSS = USB.BAS2_EL_CALC (AIR_CUR_BOOK_BAL, 0, BAS_PD, BAS_LGD, 0),
       BAS_AIR_AB_EXPECTED_LOSS = USB.BAS2_EL_CALC (AIR_AVG_BOOK_BAL, 0,BAS_PD, BAS_LGD, 0),
       BAS_DELAY_REC_EB_EXPECTED_LOSS = USB.BAS2_EL_CALC (DELAY_REC_CUR_BOOK_BAL, 0, BAS_PD, BAS_LGD, 0),
       BAS_DELAY_REC_AB_EXPECTED_LOSS = USB.BAS2_EL_CALC (DELAY_REC_AVG_BOOK_BAL, 0, BAS_PD, BAS_LGD, 0),

       BAS_TPR_EB_EXPECTED_LOSS = USB.BAS2_EL_CALC (TPR_CUR_BOOK_BAL, 0, BAS_PD, BAS_LGD, 0),
       BAS_TPR_AB_EXPECTED_LOSS = USB.BAS2_EL_CALC (TPR_AVG_BOOK_BAL, 0, BAS_PD, BAS_LGD, 0),
       BAS_UNR_EB_EXPECTED_LOSS = USB.BAS2_EL_CALC (UNR_CUR_BOOK_BAL, 0, BAS_PD, BAS_LGD, 0),
       BAS_UNR_AB_EXPECTED_LOSS = USB.BAS2_EL_CALC (UNR_AVG_BOOK_BAL, 0, BAS_PD, BAS_LGD, 0)
       WHERE
           (AS_OF_DATE = TO_DATE('06/30/2019','MM/DD/YYYY'));
COMMIT; 

END IF;


--Function: BAS_RWA_CALC logic

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

 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;
/


  [1]: https://i.stack.imgur.com/k7ikw.png

在您的 MERGE 语句中,您有 59 个函数调用。好多啊。看起来您为 MORT_BACK_SEC 中的每一行调用了 'BAS2_RWA_CALC' 27 次,即使您不使用这些调用的结果也是如此。现在,可能是数据库足够聪明,只对 MORT_BACK_SEC 中您实际最终使用的行进行那些调用,但我不会指望这一点。如果其他地方不需要它们(我没有看到它们是),我建议将这些计算推入 WHEN MATCHED 块。

您还为每次更新调用了 BAS2_MGRL_CAPITALBAS2_EL_CALC 16 次。我不知道这些函数有多复杂,但如果它们很简单并且可以用内联 CASE 表达式或类似的表达式替换,我会这样做,因为函数调用的数量会破坏性能这个说法。我不知道这会生成什么样的计划,但我怀疑它是否重要 - 我怀疑语句的 运行 时间将由所有这些函数调用的执行时间决定。

我会尝试为您重新安排您的 MERGE 语句,但我不知道哪些函数参数是 MORT_BACK_SEC 中的列,哪些是在 MERGE 之外定义的变量陈述。尝试从语句本身中提取尽可能多的函数调用(如果有的话),并且一定要将它们从初始 MERGE table 中取出。 IMO 你的 MERGE 应该以

开头
MERGE INTO MORT_BACK_SEC a
  USING RPT_ACCT_HIER b
    ON (a.GL_ACCOUNT_ID = b.ACCT_MEMBER AND
        a.AS_OF_DATE = V_DATE AND
        b.ACCT_GEN2 = 'a1000')

然后从那里拿走。

当然,因为你没有 WHEN NOT MATCHED THEN INSERT,你可以 re-do 这个作为 UPDATE 而不是 MERGE 一旦你得到所有这些功能呼叫移动到 UPDATE 块。由你决定。但同样,我怀疑它是否重要,因为我怀疑这些函数调用是该语句花费时间的地方。

有几种方法可以减少 SQL 和 PL/SQL 之间上下文切换的开销。

  1. PRAGMA UDF;在第一个is之后,在代码中添加pragma udf;告诉Oracle优化函数为SQL.在我的快速测试中,这将 SQL 调用中的上下文切换开销减少了 60%。这种方法的问题是它需要为每个人修改函数,并且在 PL/SQL.
  2. 中调用时可能会导致性能下降。
  3. 包装函数 PRAGMA UDF; 如果你不能直接修改函数,在旧函数之上创建新函数,用 pragma udf;,并在 SQL 中调用这些函数。我的测试表明这可以减少 52% 的上下文切换,这不如以前的解决方案好,但已经非常接近了。这种方法将所有原始逻辑保留在同一个地方,从而保留了 do-not-repeat-yourself 规则。但是它确实会创建新对象。
  4. PL/SQL WITH function 在 SQL 语句中创建包装函数作为通用 table 表达式。这可以减少大约 32% 的开销。这是一种 pure-SQL 方法,但它不如其他解决方案快,而且 SQL 语句看起来很难看。

这些对你不起作用,但对于未来的读者来说,最好的选择是值得注意的:

  1. 将程序 PL/SQL 代码移到声明性 SQL 代码中。
  2. 更改 PL/SQL 接口以接受批量数据,例如集合、游标、table 动态名称 SQL 等