调整过程中存在的 Execute Immediate 语句

Posted

技术标签:

【中文标题】调整过程中存在的 Execute Immediate 语句【英文标题】:Tuning Execute Immediate statements present in procedures 【发布时间】:2018-07-05 07:24:35 【问题描述】:

我想调整一个过程,该过程有许多动态 SQL 语句,这些语句执行时间过长。我需要帮助来调整这些或其他解决方案。

例子:

EXECUTE IMMEDIATE 'CREATE TABLE C1_LAN_GTT_1 NOLOGGING PARALLEL 4 AS 
SELECT /*+INDEX(C,CR_DECISION_M_CD1)*/ A.AGREEMENTID, 
       A.AGREEMENTNO, A.LESSEEID, A.PRODUCTFLAG, A.APP_FORMNO, A.AMTFIN
FROM   LEA_AGREEMENT_DTL A, CR_DECISION_M C
WHERE  A.AGREEMENTID = C.APPID
AND    A.STATUS = ''A''
AND    TRUNC(C.AUTHDATE) BETWEEN' || '''' || P_FROM_DATE || '''' ||
                       ' AND ' || '''' || P_TO_DATE || '''';

当我在 PLSQL Developer 中以调试模式检查过程时,我发现这些动态语句花费了太多时间。

查询没有数据仍然需要时间来执行。

【问题讨论】:

TRUNC(C.AUTHDATE) 可能是个问题。该列是索引的还是分区键?并且日期参数应该是格式正确的日期文字,而不是上面的。 对了,为什么不是GTT的表名为C1_LAN_GTT_1 在它可能是 GTT 之前已经存在的代码现在已经改变了 你说的是因为日期过滤器的延迟。 【参考方案1】:

没有更多详细信息,例如执行计划以及表、索引和数据量和分布的完整详细信息,我不知道您面临哪些性能问题。但是,我可能会这样开始:

declare
    p_from_date date := date '2018-01-01';
    p_to_date   date := date '2018-02-01';

    myddl long := 'create table c1_lan_gtt_1 nologging parallel 4 as 
    select /*+index(c cr_decision_m_cd1)*/ a.agreementid, 
           a.agreementno, a.lesseeid, a.productflag, a.app_formno, a.amtfin
    from   lea_agreement_dtl a
           join cr_decision_m c on c.appid = a.agreementid
    where  a.status = ''A''
    and    c.authdate between date ''' || to_char(p_from_date,'YYYY-MM-DD') || '''' ||
                    ' and date '''     || to_char(p_to_date,'YYYY-MM-DD') || '''';
begin
    dbms_output.put_line(myddl);
end;

生成

create table c1_lan_gtt_1 nologging parallel 4 as 
    select /*+index(c cr_decision_m_cd1)*/ a.agreementid, 
           a.agreementno, a.lesseeid, a.productflag, a.app_formno, a.amtfin
    from   lea_agreement_dtl a
           join cr_decision_m c on c.appid = a.agreementid
    where  a.status = 'A'
    and    trunc(c.authdate) between date '2018-01-01' and date '2018-02-01'

编辑:因为索引 CR_DECISION_M_CD1 位于 (APPID, TRUNC(AUTHDATE))(来自 cmets)我已经恢复了 trunc() 函数,即使在逻辑上它不需要。

【讨论】:

这个问题意味着这个延迟执行背后的原因,即使没有这个查询的数据。就是这样。如果你知道我可以创建表而不是这个来提高程序性能的任何其他方式。请分享 我的版本能提高性能吗?如果authdate 被索引或者是分区键,这可能是我问的原因。 我刚刚看到您对另一个答案的评论 - 索引 CR_DECISION_M_CD1(APPID, TRUNC(AUTHDATE)) 上。在这种情况下,您应该保留trunc() 函数。【参考方案2】:

检查 P_FROM_DATE 和 P_TO_DATE 是绑定变量enter link description here

【讨论】:

不幸的是,这是 DDL,因此不允许绑定变量。不过,我怀疑它是否会提高性能,因为性能问题似乎出在填充表的查询中,而不是解析中。【参考方案3】:

使用exists代替join的新版本执行立即语句:

EXECUTE IMMEDIATE 'CREATE TABLE C1_LAN_GTT_1 NOLOGGING PARALLEL 4 AS 
SELECT A.AGREEMENTID, A.AGREEMENTNO, A.LESSEEID, A.PRODUCTFLAG, A.APP_FORMNO, A.AMTFIN
FROM LEA_AGREEMENT_DTL A
WHERE A.STATUS = ''A''
AND EXISTS (
  SELECT /*+INDEX(C CR_DECISION_M_CD1)*/ NULL 
  FROM CR_DECISION_M C
  WHERE C.APPID = A.AGREEMENTID
  AND TRUNC(C.AUTHDATE) BETWEEN '''||P_FROM_DATE||''' AND '''||P_TO_DATE||'''
)';

【讨论】:

CR_DECISION_M_CD1 有这两个列:'APPID'、'TRUNC(AUTHDATE)' 您使用绑定变量共享的代码,会提高性能吗? 我尝试过使用绑定变量,但在 DDL 语句中不允许出现绑定变量等错误。请提出建议。 试用过的代码如下: DECLARE P_FROM_DATE date :=to_date('07/02/2018','mm/dd/yyyy'); P_TO_DATE 日期 :=to_date('07/02/2018','mm/dd/yyyy'); BEGIN EXECUTE IMMEDIATE 'CREATE TABLE C1_LAN_GTT_1 NOLOGGING PARALLEL 4 AS SELECT /*+INDEX(C,CR_DECISION_M_CD1)*/ A.AGREEMENTID, A.AGREEMENTNO, A.LESSEEID, A.PRODUCTFLAG, A.APP_FORMNO, A.AMTFIN FROM LEA_AGREEMENT_DTL A, finnlea_bfprod.CR_DECISION_MC WHERE A.AGREEMENTID = C.APPID AND A.STATUS = ''A'' AND TRUNC(C.AUTHDATE) BETWEEN :p_from_date AND :p_to_date' USING P_FROM_DATE, P_TO_DATE;结束; Mutturaj 是正确的 - 你不能对 DDL 使用绑定变量(如果可以的话,我看不出它会如何提高性能)。

以上是关于调整过程中存在的 Execute Immediate 语句的主要内容,如果未能解决你的问题,请参考以下文章

execute immediate

Oracle EXECUTE IMMEDIATE 未执行存储过程中的预期操作

我们应该在 Redshift 的存储过程中使用 udf

在 TableAdapter 中使用使用“EXECUTE”命令的存储过程

存储过程和权限 - EXECUTE 是不是足够?

MSSQL WAF绕过