pl / sql Хранимая процедура ... куда уходит время выполнения? - PullRequest
2 голосов
/ 26 июня 2009

В настоящее время я отслеживаю утечку производительности в хранимой процедуре. Выделение временной метки сразу после начального «начала» и одной перед конечным «концом» (я делаю коммит до ) говорит о том, что процедура занимает около. 10 секунд до конца. Однако мне нужно подождать 2 минуты +, пока он не закончится.

Кто-нибудь может сказать мне, где проходит остальное время? Я использую Oracle SQL dev, но в остальное время он не работает, кажется, процедура удерживает блокировку соответствующей таблицы: (

Заранее большое спасибо за просветление ...

РЕДАКТИРОВАТЬ: еще раз спасибо за ваш вклад :) вот раздетый код для процедуры, в зависимости от количества обрабатываемых элементов, 1-й раздел в настоящее время занимает около. От 10 до 40 секунд, 2-й раздел несколько миллисекунд. однако процедура занимает от 2 до 8 минут. Кроме того, таблица, содержащая данные для удаления, кажется, заблокирована несколько дольше, чем нужно, что приводит к отложению вставок. запуск по расписанию не имеет значения, кстати, такое же поведение.

create or replace
procedure MY_PROCEDURE is
start_procedure number;
start_delete number;
end_procedure number;
begin

  start_procedure :=dbms_utility.get_time;

  begin
  -- stripped: doing some selects/updates here
  end;
  commit;

  start_delete :=dbms_utility.get_time ;

  begin
  -- stripped: cleanig up some other data here
  end;
  commit;
  end_procedure :=dbms_utility.get_time ;

  dbms_output.put_line('procedure took: '||to_char((end_procedure- start_procedure)/1000));
  dbms_output.put_line('updates took: '||to_char((start_delete- start_procedure)/1000));
  dbms_output.put_line('delete took: '||to_char((end_procedure-start_delete)/1000));

end;

Ответы [ 11 ]

3 голосов
/ 27 июня 2009

Если вы замените эти вызовы dbms_utility.get_time на сообщения типа:

dbms_output.put_line ('start procedure: ' || to_char(sysdate, HH24:MI:SS'));

и затем вызовите процедуру следующим образом:

dbms_output.put_line ('before procedure: ' || to_char(sysdate, HH24:MI:SS'));
exec my_procedure;
dbms_output.put_line ('after procedure: ' || to_char(sysdate, HH24:MI:SS'));

тогда появится место, где происходит пропущенное время.

3 голосов
/ 26 июня 2009

Я думаю, вам нужно делить на 100, а не на 1000 (dbms_utility.get_time дает время в сантисекундах). Это должно дать вам 100 секунд, что составляет около 2 минут.

Однако, если вам интересно узнать, куда ушли 2 минуты времени выполнения, и в зависимости от сложности процедуры вы можете либо:

Профилировщик может быть лучше, если у вас много связанных вызовов процедур PL / SQL. Отчет statspack будет лучше, если в хранимой процедуре будет в основном SQL-операторы.

Вот как выглядит вывод Profiler:

Sample Report

Function Elapsed Time (microsecs) Data sorted by Total Subtree Elapsed Time (microsecs)

2831 microsecs (elapsed time) & 12 function calls
Subtree     Ind%    Function    Descendant  Ind%    Calls   Ind%    Function Name
2831    100%    93  2738    96.7%   2   16.7%   __plsq_vm
2738    96.7%   310     2428    85.8%   2   16.7%   __anonymous_block
2428    85.8%   15  2413    85.2%   1   8.3%    HR.TEST.TEST (Line 1)
2413    85.2%   435     1978    69.9%   3   25.0%   HR.TEST.TEST.FOO (Line 3)
1978    69.9%   1978    0   0.0%    3   25.0%   HR.TEST.__static_sql_exec_line5 (Line 5)
0   0.0%    0   0   0.0%    1   8.3%    SYS.DBMS_HPROF.STOP_PROFILING (Line 53)
2 голосов
/ 27 июня 2009

Я не знаком с pl / sql, но есть ли способ приостановить или прервать его во время работы?

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

В общем, метод такой.

1 голос
/ 28 июня 2009

В ваших инструкциях DBMS_OUTPUT вы делите свой результат на 1000. Согласно всей документации Oracle, которую я могу найти в функции dbms_utility.get_time, измерьте время в сотых долях секунды, а не в тысячных.

Таким образом, в то время как вы отображаете от 10 до 40 секунд, на самом деле это от 100 (1 минута 40 секунд) до 400 (6 минут 40 секунд) секунд. Это больше соответствует 2-8 минутам, которые вы наблюдаете.

Проверьте http://download -west.oracle.com / docs / cd / B19306_01 / appdev.102 / b14258 / d_util.htm для получения дополнительной информации о функции.

1 голос
/ 26 июня 2009

В разделе объявлений может быть что-то, что может занять много времени. Не могли бы вы включить код вашей хранимой процедуры?

0 голосов
/ 29 июня 2009

Oracle содержит профилировщик, который сообщит вам количество времени, потраченное на каждый исполняемый оператор. dbms_profiler для 10g и более ранних версий, и есть более интересная версия (иерархический профилировщик), доступная в 11g.

Гораздо проще, чем использование наборов операторов dbms_utility и dbms_output, и это дает вам гораздо более полную информацию - включая детализацию вызываемых подпрограмм, если у вас есть права на просмотр их исходного кода.

Я рад, что ты решил свою проблему. В следующий раз, тем не менее, с помощью профилировщика будет легче.

0 голосов
/ 27 июня 2009

Проблема решена, но я до сих пор не понимаю ...

Утечка была вызвана неверным оператором select, похороненным в другой процедуре, которая вызывается другой процедурой. Я оптимизировал его, теперь он работает как шарм.

Я нашел трудный путь, комментируя построчно ... пытаясь и пытаясь.

Однако я все еще хотел бы знать, почему отметки времени были абсолютно неточными. Это вводило в заблуждение и стоило мне довольно много времени ... Итак, что-то не так с тем, как я создаю метки времени?

Если у кого-то есть информация по этому поводу, я буду рад ее услышать.

Спасибо всем вам за помощь в решении этой проблемы.

0 голосов
/ 27 июня 2009

Что делает процедура? Одним из возможных объяснений может быть DBMS_OUTPUT. Если в SQL * Plus вы делаете SET SERVEROUTPUT ON, после выполнения оператора клиент выполняет «закулисную» выборку любой информации, которая была буферизована с использованием DBMS_OUTPUT.PUT_LINE. Я предполагаю, что SQL Developer делает то же самое.

Так что, если в DBMS_OUTPUT было передано много материала, выполнение процедуры может быть быстрым, но закулисный сбор этого может занять время (особенно если это медленная сеть) .

Еще один трюк в SQL * Плюс, вы можете SET TIMING ON (который автоматически покажет истекшее время выписки) а также УСТАНОВИТЬ ВРЕМЯ ВКЛ (которое показывает время в приглашении SQL).

Так что попробуйте

SET SERVEROUTPUT OFF
SET TIMING ON
SET TIME ON
DBMS_MONITOR.DATABASE_TRACE_ENABLE(TRUE);
exec stored_proc;
disconn

И посмотрите результаты. Я не ожидал бы увидеть какое-то время без вести пропавшим. То есть клиент должен сообщить полные две минуты. Предполагая, что это так, я бы использовал трассировку (команда DBMS_MONITOR) и запустил tkprof для результата, чтобы увидеть, что отвечает за эти 2 минуты.

0 голосов
/ 26 июня 2009

Так что-то вроде этого?

CREATE PROCEDURE ...
AS
DECLARE some stuff
BEGIN
    print time
    do stuff
    COMMIT
    print time
END

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

Такое поведение было бы аналогично тому, как действуют ограничения на ссылочную целостность DEFERRABLE INITALLY DEFERRED.

Я подозреваю, что предложенные запросы системных таблиц скажут вам, или вы можете попробовать выполнить шаги "do stuff" в интерактивном сеансе и посмотреть, что произойдет.

0 голосов
/ 26 июня 2009

если у вас есть соответствующие разрешения (и если нет, обратитесь к dba за помощью), возможно, вы могли бы запросить следующие представления:

V$SESSION_WAIT
V$SYSTEM_EVENT

Вы можете проверить результаты

здесь (http://www.remote -dba.net / oracle_10g_tuning / t_oracle_v $ session_wait.htm) * - описание того, как читать выходные данные, а здесь - некоторая дополнительная информация на события внутри.

* вам придется скопировать URL, так как $ портит ссылку.

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