Процедура Plsql говорить вечно бежать - PullRequest
0 голосов
/ 06 октября 2018

Эта процедура прекрасно компилируется, но выполняется вечно.Я думаю, что даже для одного ряда это занимает слишком много времени для обработки.Где мне изменить код, чтобы он работал быстрее?

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 голосов
/ 06 октября 2018

Некоторые общие рекомендации по исследованию производительности 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 с помощью SQL Monitor .Если у вас есть доступ к нему, Oracle Enterprise Manager / Cloud Control предоставит вам многое из этого через удобную панель управления на основе браузера.Я также взял бы каждый оператор SQL и протестировал его в командной строке, чтобы убедиться, что он выполнил то, что ожидал, и выполнил за разумное время.
0 голосов
/ 06 октября 2018

Вы используете 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;

Обратите внимание, что код не проверен , поэтому вам, возможно, придется исправить некоторые синтаксические ошибки / ошибки редактирования, которые я, возможно, допустил.Но я думаю, что дал вам достаточно справедливое представление о том, как действовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...