Oracle PL/SQL — советы по немедленному выводу/печати в консоль

У меня есть несколько процедур pl/sql, выполнение которых может занять несколько минут. При их разработке я добавил несколько операторов печати, чтобы помочь в отладке, а также предоставить некоторые отзывы и индикаторы прогресса. Сначала я запускал их на небольших тестовых наборах, и результат был почти мгновенным. Теперь, когда я тестирую большие наборы тестов, запуск которых занимает несколько минут, я обнаружил, что печать на консоль больше не подходит, потому что ничего не печатается, пока процедура не завершится. Я привык работать в средах, которые не буферизуют свои выходные данные и не распечатывают их немедленно, а добавление простых операторов печати для простой отладки и диагностики является обычным явлением.

Возможно ли в pl/sql немедленно распечатать вывод (без буферизации)? Если нет, то какие альтернативы люди рекомендуют для получения аналогичного результата?


person FrustratedWithFormsDesigner    schedule 13.11.2009    source источник


Ответы (8)


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

procedure log (p_message)
is
    pragma autonomous_transaction;
begin
    insert into message_log (user, datetime, message)
    values (user, sysdate, p_message);
    commit;
end;

Затем отслеживайте таблицу из другого сеанса Oracle.

person Tony Andrews    schedule 13.11.2009
comment
Дополнительная информация о прагме AutonomousTransaction stackoverflow.com/questions/1335331/autonomoustransaction - person berlebutch; 13.11.2009
comment
Это выглядит хорошо, я, вероятно, попробую это сегодня :) Как это соотносится с другим предложением использовать трубы? Что будет легче просматривать и контролировать? - person FrustratedWithFormsDesigner; 16.11.2009
comment
Я не использовал метод трубы, поэтому не могу комментировать это. Одно отличие от табличного метода заключается в том, что сообщения являются постоянными. Это может быть преимуществом, но это также означает, что вы должны управлять ими, чтобы таблица не росла бесконечно! - person Tony Andrews; 16.11.2009
comment
Я собираюсь принять этот ответ, поскольку настойчивость может стать серьезной проблемой (в том смысле, что она нам понадобится!) В дальнейшем, но идея с каналами и даже идея с конвейерной функцией была интересной. Если у меня будет время простоя, мне придется попробовать их все! - person FrustratedWithFormsDesigner; 17.11.2009

у нас есть небольшая хитрость для этого.

вы можете использовать DBMS_APPLICATION_INFO.set_client_info("некоторая информация здесь"); создание некоторых переменных и замена строки внутри " ".

и используйте select client_info из v$session для отслеживания хода выполнения.

person Henry Gao    schedule 13.11.2009
comment
У меня есть доступ к v$session_longops и v$session_connect_info, и ни в одном из них нет поля client_info. Будет ли v$session_longops столь же хорош? - person FrustratedWithFormsDesigner; 13.11.2009
comment
нет, вам нужно использовать представление v$session. спросите у администратора базы данных, если у вас нет доступа. - person Henry Gao; 13.11.2009

Для этой цели я использовал dbms_pipe. Отправляйте сообщения в именованный канал и читайте их из другого сеанса. Этот метод может не работать в среде RAC, когда процессы записи и чтения могут подключаться к другому узлу.

В качестве альтернативы вы можете вставлять сообщения в таблицу, используя процедуру, которая запускается в своем собственном сеансе, используя «прагму автономная_транзакция». Вы можете запросить эти сообщения из другого сеанса

Изменить: я вижу, что мой второй вариант уже упоминался.

person Rene    schedule 16.11.2009
comment
Обе эти возможности выглядят интересными, хотя я получаю сообщение об ошибке (вероятно, связанное с разрешениями), когда пытаюсь использовать пакет dbms_pipe. Каковы плюсы и минусы каждого подхода? Я мало что знаю о каналах Oracle, поэтому не знаю, как это оценить, но это выглядит ближе к тому, что я хочу, чем решение на основе таблиц. - person FrustratedWithFormsDesigner; 16.11.2009

Обычно есть два варианта:

  • Отправить вывод в таблицу Oracle (или временную таблицу)
  • Запись в файловую систему (хост базы данных) с UTL_FILE

Если у вас нет доступа ОС к хосту базы данных, вы все равно можете писать в файловую систему dbhost и привязывать внешне определенную таблицу Oracle к файлу, чтобы ее можно было запрашивать с помощью SELECT.

person dpbradley    schedule 13.11.2009

Это может зависеть от вашего клиентского инструмента. Я давно не использовал SQL*Plus, но когда я отлаживаю процедуры в PL/SQL Developer, я открываю командное окно и запускаю команду SET SERVEROUTPUT ON. Затем, когда я выполняю процедуру, все, что напечатано DBMS_OUTPUT.PUT_LINE, сразу же появляется.

Редактировать: вы правы, я думаю, я видел это только с большими объемами вывода или что-то в этом роде. Во всяком случае, я немного поискал в Интернете и наткнулся на этот log4plsql - может оказаться полезным.

person Dan    schedule 13.11.2009
comment
Я использую PL/SQL Developer, это не работает. Весь вывод печатается сразу после завершения выполнения скрипта. - person FrustratedWithFormsDesigner; 13.11.2009

Альтернативой является использование конвейерной функции, которая возвращает данные журнала. См. пример здесь: http://berxblog.blogspot.com/2009/01/pipelined-function-vs-dbmsoutput.html Когда вы используете конвейерную функцию, вам не нужно использовать другой сеанс разработчика SQLPLUS/Toad/sql и т. д..

person tuinstoel    schedule 13.11.2009
comment
Это интересно, но не придется ли мне модифицировать мою существующую функцию, чтобы сделать ее конвейерной, или, возможно, обернуть ее в конвейерную функцию? - person FrustratedWithFormsDesigner; 16.11.2009
comment
Конечно, вы должны изменить свой код. Просто обернуть его внутри конвейерной функции вам не поможет, потому что вы хотите немедленное ведение журнала, а не только ведение журнала, когда что-то делается. - person tuinstoel; 16.11.2009

Вы можете использовать DBMS Pipe и средство просмотра Pipe Viewer в PL/SQL Developer, чтобы асинхронно перехватывать всю информацию, когда она помещается в канал.

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

Также есть возможность использования событий, PL/SQL Developer также имеет монитор событий. И документы должны предоставить пример того, как это сделать.

person Robert Giesecke    schedule 16.11.2009
comment
Это выглядит хорошо, но я получаю сообщение об ошибке: должен быть объявлен идентификатор 'DBMS_PIPE', я думаю, мне нужно поговорить об этом с администратором базы данных. Вероятно, проблема с разрешениями. - person FrustratedWithFormsDesigner; 16.11.2009

Другой вариант — заставить ваш PL/SQL вызывать процедуру для отправки сообщения электронной почты с сообщением журнала. Для этого требуется, чтобы ваша база данных имела возможность отправки электронной почты, которую можно добавить с помощью UTL_SMTP.

person Leigh Riffel    schedule 17.02.2010