2013-06-25 4 views
0

Я написал блок PL/SQL, который работает в Oracle 9i, в то время как он работает с данными из Oracle Database 11g по ссылке DB. Но код завершает forver. Обработанные данные составляют от 1000 до 2000 записей. Я размещаю код здесь:Улучшение производительности PL/SQL

DECLARE 
    v_last_comment VARCHAR2 (255); 
    v_check   NUMBER   := 0; 

    CURSOR noschedule_progs 
    IS 
     SELECT /*+ DRIVING_SITE(fcr) */ 
      fcr.request_id, 
      DECODE 
       (fcpt.user_concurrent_program_name, 
       'Report Set', fcr.description, 
       'Request Set Stage', fcr.description, 
       fcpt.user_concurrent_program_name 
       ) user_concurrent_program_name, 
      fcr.description, fcr.argument_text, fcr.concurrent_program_id, 
      fcr.parent_request_id, fcr.actual_start_date, 
      fcr.actual_completion_date, 
      ROUND ( (fcr.actual_completion_date - fcr.actual_start_date) 
        * 24 
        * 60, 
        4 
        ) runtime, 
      'No Schedule' program_status, fu.user_name, 
      frt.responsibility_name, fcr.logfile_name 
     FROM [email protected]_link fcr, 
      [email protected]_link fcpt, 
      [email protected]_link fu, 
      [email protected]_link frt 
     WHERE fcr.concurrent_program_id = fcpt.concurrent_program_id 
     AND fcr.requested_by = fu.user_id 
     AND fcr.responsibility_id = frt.responsibility_id 
     AND fcr.responsibility_application_id = frt.application_id 
     AND fcr.phase_code = 'C' 
     AND fcr.status_code IN ('C', 'G', 'E', 'X') 
     AND fcr.actual_completion_date >= SYSDATE - 1/24 
     AND fcr.request_id NOT IN (
          SELECT NVL (parent_request_id, 1) 
           FROM [email protected]_link) 
     AND fcr.requested_by = 1508715 
     AND fcr.request_id NOT IN (SELECT request_id 
             FROM allen.alert_main 
            WHERE program_status = 'No Schedule'); 

    PROCEDURE check_schedule (p_request_id IN NUMBER) 
    IS 
     v_count    NUMBER (2); 
     v_parent_id   NUMBER (15); 
     v_last_updated_by NUMBER (15); 
     v_program   VARCHAR2 (255); 
     v_parent_program VARCHAR2 (255); 
     v_description  VARCHAR2 (255); 
     v_status   VARCHAR2 (2); 
    BEGIN 
     SELECT NVL (MAX (phase_code), 'X') 
     INTO v_status 
     FROM [email protected]_link 
     WHERE request_id = p_request_id; 

     IF v_status != 'R' 
     THEN 
     SELECT NVL (MAX (description), 'None') 
      INTO v_description 
      FROM [email protected]_link 
      WHERE request_id = p_request_id; 

     SELECT COUNT (*) 
      INTO v_count 
      FROM [email protected]_link 
      WHERE parent_request_id = p_request_id 
      AND concurrent_program_id = 
          (SELECT concurrent_program_id 
          FROM [email protected]_link 
          WHERE request_id = p_request_id) 
      AND NVL (description, 'None') = v_description; 

     IF v_count = 0 
     THEN 
      SELECT NVL (MAX (parent_request_id), 1) 
       INTO v_parent_id 
       FROM [email protected]_link 
      WHERE request_id = p_request_id; 

      SELECT NVL (MAX (last_updated_by), 0) 
       INTO v_last_updated_by 
       FROM [email protected]_link 
      WHERE request_id = p_request_id; 

      IF v_parent_id = -1 
      THEN 
       IF v_last_updated_by != 4 
       THEN 
        INSERT INTO ikndba.rac_aso_alert_main 
        SELECT /*+ DRIVING_SITE(fcr) */ 
          ikndba.rac_aso_alert_seq.NEXTVAL, fcr.request_id, 
          DECODE 
           (fcpt.user_concurrent_program_name, 
           'Report Set', fcr.description, 
           'Request Set Stage', fcr.description, 
           fcpt.user_concurrent_program_name 
           ) user_concurrent_program_name, 
          fcr.argument_text, fcr.concurrent_program_id, 
          fcr.parent_request_id, fcr.actual_start_date, 
          fcr.actual_completion_date, 
          ROUND ( ( fcr.actual_completion_date 
             - fcr.actual_start_date 
            ) 
            * 24 
            * 60, 
            4 
           ) runtime, 
          'No Schedule' program_status, fu.user_name, 
          frt.responsibility_name, fcr.logfile_name, 
          SYSDATE, 'Program Not in Schedule', NULL, 'OPEN', 
          'SYSTEM' 
         FROM [email protected]_link fcr, 
          [email protected]_link fcpt, 
          [email protected]_link fu, 
          [email protected]_link frt 
         WHERE fcr.concurrent_program_id = 
                fcpt.concurrent_program_id 
         AND fcr.requested_by = fu.user_id 
         AND fcr.responsibility_id = frt.responsibility_id 
         AND fcr.responsibility_application_id = 
                  frt.application_id 
         AND fcr.request_id = p_request_id 
         AND fcr.request_id NOT IN (
           SELECT request_id 
           FROM allen.alert_main 
             WHERE program_status = 'No Schedule'); 
       commit 
       END IF; 
      ELSE 
       SELECT NVL (MAX (DECODE (fcpt.user_concurrent_program_name, 
             'Report Set', fcr.description, 
             'Request Set Stage', fcr.description, 
             fcpt.user_concurrent_program_name 
             ) 
           ), 
          'Purged' 
         ) 
       INTO v_program 
       FROM [email protected]_link fcr, 
         [email protected]_link fcpt 
       WHERE request_id = p_request_id 
        AND fcr.concurrent_program_id = fcpt.concurrent_program_id; 

       SELECT NVL (MAX (DECODE (fcpt.user_concurrent_program_name, 
             'Report Set', fcr.description, 
             'Request Set Stage', fcr.description, 
             fcpt.user_concurrent_program_name 
             ) 
           ), 
          'Purged' 
         ) 
       INTO v_parent_program 
       FROM [email protected]_link fcr, 
         [email protected]_link fcpt 
       WHERE request_id = v_parent_id 
        AND fcr.concurrent_program_id = fcpt.concurrent_program_id; 

       IF v_parent_program = v_program AND v_program != 'Purged' 
       THEN 
        INSERT INTO ikndba.rac_aso_alert_main 
        SELECT /*+ DRIVING_SITE(fcr) */ 
          ikndba.rac_aso_alert_seq.NEXTVAL, fcr.request_id, 
          DECODE 
           (fcpt.user_concurrent_program_name, 
           'Report Set', fcr.description, 
           'Request Set Stage', fcr.description, 
           fcpt.user_concurrent_program_name 
           ) user_concurrent_program_name, 
          fcr.argument_text, fcr.concurrent_program_id, 
          fcr.parent_request_id, fcr.actual_start_date, 
          fcr.actual_completion_date, 
          ROUND ( ( fcr.actual_completion_date 
             - fcr.actual_start_date 
            ) 
            * 24 
            * 60, 
            4 
           ) runtime, 
          'No Schedule' program_status, fu.user_name, 
          frt.responsibility_name, fcr.logfile_name, 
          SYSDATE, 'Program Not in Schedule', NULL, 'OPEN', 
          'SYSTEM' 
         FROM [email protected]_link fcr, 
          [email protected]_link fcpt, 
          [email protected]_link fu, 
          [email protected]_link frt 
         WHERE fcr.concurrent_program_id = 
                fcpt.concurrent_program_id 
         AND fcr.requested_by = fu.user_id 
         AND fcr.responsibility_id = frt.responsibility_id 
         AND fcr.responsibility_application_id = 
                  frt.application_id 
         AND fcr.request_id = p_request_id 
         AND fcr.request_id NOT IN (
              SELECT request_id 
              FROM allen.alert_main 
              WHERE program_status = 
                   'No Schedule'); 

        COMMIT; 
       ELSE 
       SELECT NVL (MAX (parent_request_id), 1) 
       INTO v_parent_id 
       FROM [email protected]_link 
      WHERE request_id =v_parent_id; 
        check_schedule (v_parent_id); 
       END IF; 
      END IF; 
     END IF; 
     END IF; 
    END; 
BEGIN 
    FOR noschedule_progs_row IN noschedule_progs 
    LOOP 
     check_schedule (noschedule_progs_row.request_id); 
    END LOOP; 
COMMIT; 
EXCEPTION 
    WHEN OTHERS 
    THEN 
     ROLLBACK; 
     DBMS_OUTPUT.put_line (SQLCODE); 
END; 
/

Есть ли способ повысить эффективность этой программы?

+7

Я не знаю о других, но я редко терпении вопросов со стенами коды.К вашему кредиту, по крайней мере, он отлично отформатирован. –

+3

Можете ли вы сузить, какие части занимают некоторое время? Это межсетевое общение или заявления, запущенные с обоих концов? Это не обязательно поможет в производительности, но вы всегда должны явно квалифицировать свои объединения, не используйте неявный (разделенный запятыми 'предложение' FROM') синтаксис. И, конечно же, использование циклов и условных выражений не поможет повышению производительности ... У меня также плохое представление о том, сколько транзакций вы можете пройти - вам может быть повезло, если вы сделали это в одном –

+0

Используйте PL/SQL Profiler, чтобы найти компоненты, которые стоит оптимизировать. У вашей IDE, вероятно, есть GUI, чтобы сделать это для вас. –

ответ

0

Кажется, что эта таблица: apps.fnd_concurrent_requests выбирается несколько раз в этой процедуре. попытайтесь поместить соответствующие данные в предложение WITH в начале процедуры, чтобы избежать ненужных операций ввода-вывода в этой таблице. вы можете найти более подробную информацию о статье WITH here

1

Вы разместили длинную стяжку кода и никаких фактических данных (профиль производительности, объемы данных, бизнес-логику и т. Д.). Так что лучше всего вы можете надеяться на некоторые общие наблюдения.


Ваша процедура содержит несколько сложных запросов, которые имеют общий атрибут: почти все таблицы основаны на удаленной базе данных. Вы не можете настроить эти запросы.

Вернее, вы не можете настроить их удаленно. Вам нужно настроить запросы локально, то есть в базе данных, где находятся таблицы. После того, как вы настроите запросы, вы можете создавать их вокруг них и использовать их в своей процедуре.

Фактически, это было бы хорошей отправной точкой. Часто проблема производительности распределенных запросов связана с затратами на передачу ненужных данных по ссылке базы данных. Гораздо эффективнее фильтровать данные в домашней базе данных и только транспортные фильтры.

Очень вероятно, что вы оплачиваете эту транспортную стоимость, потому что вы соединяете эти удаленные таблицы с местным столом, allen.alert_main. Поэтому вам необходимо обработать это: либо включить его в представления (в виде удаленной таблицы), либо удалить подзапрос из представления и просто ссылаться на него в процедуре.

Я полагаю, что удаленная база данных является системой Oracle Apps. Это может создать некоторые ограничения на то, что вам разрешено делать.

Другая возможная неэффективность: выполнение выбирает несколько раз вместо одного раза. Это ...

 SELECT NVL (MAX (parent_request_id), 1) 
      INTO v_parent_id 
      FROM [email protected]_link 
     WHERE request_id = p_request_id; 

     SELECT NVL (MAX (last_updated_by), 0) 
      INTO v_last_updated_by 
      FROM [email protected]_link 
     WHERE request_id = p_request_id; 

... может быть это ...

 SELECT NVL (MAX (parent_request_id), 1), NVL (MAX (last_updated_by), 0) 
      INTO v_parent_id, v_last_updated_by 
      FROM [email protected]_link 
     WHERE request_id = p_request_id; 

Хотя это предположение: иногда две отдельные чтения являются более эффективными, чем в сочетании чтения, в зависимости от индексов и т.д. Но вы так много делаете, поэтому стоит исследовать.

0

Создать или заполнить временную таблицу resuslt на удаленной базе данных можно также использовать MV. Помещенный оператор вставки в процедуру разделительного Не используйте фиксации для каждой записи поместить еще некоторые комментарии в коде