plsql程序永远说话运行

时间:2018-10-06 03:26:56

标签: sql oracle stored-procedures plsql

此过程编译良好,但是要花很多时间才能运行。我认为即使是单行处理,也要花费太多时间。我应该在哪里更改代码以使其运行更快?

CREATE OR REPLACE PROCEDURE NEWWAPTWOPROC(
  P_WAP NUMBER,
  P_DEALNO VARCHAR2,
  P_FDT DATE, 
  P_SECURITYCD VARCHAR2,
  P_SECURITYTYPE VARCHAR2,
  P_SELFORCONSTITUENT VARCHAR2
)
IS
  v_pofv NUMBER(30);
  v_sofv NUMBER(30);
CURSOR C1 IS 
SELECT
     D.SECURITYCD SCD,
   D.DEALNO DNO,
   S.OWNSTK OWNST,
   LAG(S.OWNSTK) OVER(ORDER BY D.DEALDT) PC_STK,
   D.Dealtype DTYPE,
     D.SECURITYTYPE STYPE,
     D.SELFORCONSTITUENT SFORCO,
     D.DEALDT DDATE , 
     D.PRICE PRC,
     D.FACEVALUE FV,
     LAG(D.FACEVALUE) OVER(ORDER BY D.DEALDT) PC_FV,
     D.WAP1 WP,
     LAG(D.WAP1) OVER(ORDER BY D.DEALDT) PC_WAP1
FROM MMDEAL0_NWAP D INNER JOIN Mmstock1 S
  ON D.Securitycd=S.Securitycd
  WHERE D.DEALDT>=P_FDT
  AND D.DEALNO=P_Dealno
  AND D.FACEVALUE>0
  AND D.Dealtype IN('PO','SO')
  AND D.Selforconstituent='S'
  AND D.SECURITYTYPE='DGS'
  ORDER BY 
     D.DEALDT,D.Securitycd;

BEGIN

FOR i in C1
LOOP
    if C1%rowcount=1 then
      UPDATE MMDEAL0_NWAP SET WAP1=P_WAP WHERE Dealno=P_DEALNO AND DEALDT=P_FDT AND
      SECURITYCD=P_SECURITYCD AND SECURITYTYPE=P_SECURITYTYPE AND
      Selforconstituent=P_SELFORCONSTITUENT;

    else
       IF i.OWNST>0 then
            if i.DTYPE='PO' then
              v_pofv:=i.FV;
            elsif i.DTYPE='SO' then
              v_sofv:=i.FV;
            end if;
        i.WP:=((nvl(i.PC_WAP1,0)*nvl(i.PC_STK,0))+(nvl(v_pofv,0)*nvl(i.PRC,0)))-(nvl(v_sofv,0)*nvl(i.PC_WAP1,0))/i.OWNST;

        UPDATE MMDEAL0_NWAP SET WAP1=i.WP WHERE DEALNO=i.DNO AND DEALDT=i.DDATE AND 
        SECURITYCD=i.SCD AND SECURITYTYPE=i.STYPE AND SELFORCONSTITUENT= i.SFORCO;
       END IF;
    end if;
END LOOP;

EXCEPTION
WHEN OTHERS THEN
Dbms_Output.Put_Line(SQLCODE||' '||SQLERRM);
END NEWWAPTWOPROC;

2 个答案:

答案 0 :(得分:3)

您正在使用CURSOR并在所有更新都可以转换为更新和MERGE语句时无故循环。

以下是您对案例C1%rowcount=1的更新声明,甚至在之前也不需要将其放入循环中。

UPDATE mmdeal0_nwap 
SET    wap1 = p_wap 
WHERE  dealno = p_dealno 
       AND dealdt = p_fdt 
       AND securitycd = p_securitycd 
       AND securitytype = p_securitytype 
       AND selforconstituent = p_selforconstituent;   

第二次更新已转换为MERGE

MERGE INTO mmdeal0_nwap t USING (
     SELECT i.*,
            ( ( nvl(i.pc_wap1,0) * nvl(i.pc_stk,0) ) + ( nvl(v_pofv,0) * nvl(i.prc,0) ) ) - ( nvl(v_sofv
           ,0) * nvl(i.pc_wap1,0) ) / i.ownst AS new_wp  --your calculation for the value of WP to be updated
     FROM (
          SELECT d.securitycd scd,
                 d.dealno dno,
                 s.ownstk ownst,
                 LAG(s.ownstk) OVER(
                      ORDER BY d.dealdt
                 ) pc_stk,
                 d.dealtype dtype,
                 d.securitytype stype,
                 d.selforconstituent sforco,
                 d.dealdt ddate,
                 d.price prc,
                 d.facevalue fv,
                 LAG(d.facevalue) OVER(
                      ORDER BY d.dealdt
                 ) pc_fv,
                 d.wap1 wp,
                 LAG(d.wap1) OVER(
                      ORDER BY d.dealdt
                 ) pc_wap1,
                 CASE
                      WHEN d.dealtype = 'PO' THEN d.facevalue
                 END
            AS v_pofv,
                 CASE
                      WHEN d.dealtype = 'SO' THEN d.facevalue      -- IF conditions converted to CASE
                 END
            AS v_sofv
          FROM mmdeal0_nwap d
          INNER JOIN mmstock1 s ON d.securitycd = s.securitycd
          WHERE d.dealdt >= p_fdt AND d.dealno = p_dealno AND d.facevalue > 0 AND d.dealtype IN (
               'PO',
               'SO'
          ) AND d.selforconstituent = 'S' AND d.securitytype = 'DGS'
     ) i
     WHERE i.ownst > 0                              --outer IF condition
)
ON (
     t.dealno = s.dno AND t.dealdt = s.ddate AND t.securitycd = s.scd AND t.securitytype = s.stype AND
     t.selforconstituent = s.sforco
)   --where clause from your update
WHEN MATCHED THEN UPDATE SET t.wap1 = s.new_wp;

请注意,代码是 unested ,因此您可能必须修复一些我可能犯的语法错误/编辑错误。但是,我相信我已经给了您足够的想法,该如何进行。

答案 1 :(得分:0)

有关调查PL / SQL性能的一些一般建议:

  1. 添加dbms_output条包含计数和计时的消息(或将详细信息写入日志表)。如果代码永远不会完成或产生太多输出,这可能会很棘手,但是您可以创建一些简化的测试数据来限制运行。
  2. 在调试器中逐步执行代码,直到您可以识别出问题为止,例如,如果某个值未按预期重置或没有退出循环。它还可以让您感觉到每个步骤需要花费多长时间。 (台式机工具以不同的方式启动调试器,但它们都应提供该功能。)
  3. 使用dbms_profiler获取有关每个语句被调用多少次以及花费多少时间的报告。同样,您可能需要使用简化的测试数据来限制运行。性能分析内置于某些桌面工具(例如PL / SQL Developer)中,因此您只需单击一个按钮,否则就可以在命令行中直接使用它。 (还有dbms_hprof,虽然使用起来几乎没有好处,但还有dbms_trace,尽管以我的经验,这并不能告诉您任何有用的信息。)
  4. 您可以通过从另一个会话中查询v$session来了解很多事情。某些台式机工具内置有会话监视器,以使此操作变得更容易。
  5. 如果您已获得诊断和调整包的许可,则可以从v$active_session_history中获得很多有用的运行时信息。
  6. 您可以使用SQL Monitor监视正在运行或最近完成的SQL。如果您可以访问它,则Oracle Enterprise Manager / Cloud Control会通过基于浏览器的便捷仪表板为您提供很多帮助。我还将接受每个SQL语句,并在命令行上对其进行测试,以确保它在合理的时间内达到了我的期望并完成了任务。