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

时间:2019-07-17 20:18:54

标签: oracle plsql toad

我已经根据前端应用程序传递的输入编写了PL / SQL代码来更新表的列,例如如果https://,则以下块将运行。我有90多个这样的应用程序,并在过程中运行更新。在fetch()中对其进行测试期间,尽管代码工作正常并且可以完成预期的工作,即先将列值设置为零,然后再调用几个函数进行财务处理计算,它花费的时间太长(超过一个小时)。最初,我认为这是因为有数以百万计的行/数据,但是我将其发布在此处,以检查代码是否有进一步改进的可能,以减少执行时间。

提前感谢您的帮助!

PS:我无法更改函数,例如INSTTABLE = 8内部calc / return值,因为它在prod中被许多其他proc使用,因此我在单独的update语句中将列设置为0 ,然后进行主要更新。将其设置为零的原因是生产遵循相同的逻辑,即先将列设置为0,然后再进行计算。如果我不这样做,则比较查询会有所不同。

dev environment
BAS2_RWA_CALC

2 个答案:

答案 0 :(得分:1)

在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表中删除。 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,因此您可以将所有这些函数调用移至UPDATE中,而不用MERGE来重做。 UPDATE块。由你决定。但是我再次怀疑这很重要,因为这些函数调用是我怀疑该语句花费时间的地方。

好运。

答案 1 :(得分:1)

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

  1. PRAGMA UDF; 在第一个is之后,在代码中添加pragma udf;,以告诉Oracle优化SQL函数。在我的快速测试中,这将SQL调用中的上下文切换开销减少了60%。这种方法的问题在于,它需要修改每个人的功能,并且在PL / SQL中调用时可能会导致性能下降。
  2. 带有PRAGMA UDF;的包装函数如果无法直接修改该函数,请在旧函数之上创建新函数,并使用pragma udf;创建它们,然后调用它们SQL中的函数。我的测试表明,这可以将上下文切换减少52%,虽然不如以前的解决方案好,但是非常接近。这种方法将所有原始逻辑保留在同一位置,从而保留了“不重复自己”规则。但是,它确实会创建新对象。
  3. PL / SQL WITH函数在SQL语句中将包装函数创建为公用表表达式。这样可以将开销减少大约32%。这是一种纯SQL方法,但是没有其他解决方案快,并且SQL语句看起来很丑。

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

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