PL/pgSQL
Отладка
12
Авторские права
© Postgres Professional, 2017–2021
Авторы: Егор Рогов, Павел Лузанов
Использование материалов курса
Некоммерческое использование материалов курса (презентации,
демонстрации) разрешается без ограничений. Коммерческое
использование возможно только с письменного разрешения компании
Postgres Professional. Запрещается внесение изменений в материалы
курса.
Обратная связь
Отзывы, замечания и предложения направляйте по адресу:
Отказ от ответственности
Компания Postgres Professional не несет никакой ответственности за
любые повреждения и убытки, включая потерю дохода, нанесенные
прямым или непрямым, специальным или случайным использованием
материалов курса. Компания Postgres Professional не предоставляет
каких-либо гарантий на материалы курса. Материалы курса
предоставляются на основе принципа «как есть» и компания Postgres
Professional не обязана предоставлять сопровождение, поддержку,
обновления, расширения и изменения.
2
Темы
Проверки корректности
Отладчик PL/pgSQL
Служебные сообщения и различные способы их реализации
Трассировка сеансов
3
Проверки корректности
Проверки времени компиляции и времени выполнения
plpgsql.extra_warnings
plpgsql.extra_errors
дополнительные проверки в расширении plpgsql_check
Проверки в коде
команда ASSERT
Тестирование
Отладка предполагает выполнение программы и изучение
возникающих проблем, обычно с помощью специализированного
отладчика или с помощью вывода отладочных сообщений.
Но можно заранее исключить определенные классы ошибок, включив
проверку исходного кода во время компиляции и выполнения. Это
управляется параметрами plpgsql.extra_warnings и plpgsql.extra_errors,
как рассматривалось в теме «PL/pgSQL. Выполнение запросов».
Там же рассматривалось применение расширения plpgsql_check,
которое обеспечивает более широкий спектр проверок.
Еще одна возможность обезопасить свой код — добавить в него
проверки условий, которые всегда должны выполняться (т. н. «sanity
check»). Удобный способ для этого — SQL-команда ASSERT.
Нельзя не сказать и о важности тестирования кода. Тестирование не
только позволяет изначально убедиться, что код работает так, как
задумано, но и облегчает его дальнейшую модификацию — дает
уверенность в том, что изменения не поломали существующий
функционал. Мы не будем углубляться в эту тему; отметим только, что
тестирование кода, работающего с базой данных, может оказаться
непростым делом из-за необходимости подготовки тестовых примеров.
5
PL/pgSQL Debugger
Интерфейс
расширение pldbgapi предоставляет API
пользовательский интерфейс в некоторых графических средах
Возможности
установка точек прерывания
пошаговое выполнение
проверка и установка значений переменных
не требуется изменение кода
отладка работающих приложений
PL/pgSQL Debugger — это отладчик для PL/pgSQL. Представляет
собой расширение pldbgapi, которое официально поддерживается
разработчиками PostgreSQL.
Расширение pldbgapi — это набор интерфейсных функций для сервера
PostgreSQL, которые позволяют устанавливать точки прерывания,
пошагово выполнять код программ, проверять и устанавливать
значений переменных.
Исходный код отлаживаемых программ изменять не требуется, что
дает возможность выполнять отладку работающих приложений. Т. е.
отлаживаемый процесс не обязательно запускать отдельно, можно
подключиться к уже работающему сеансу и начать его отладку.
Непосредственно пользоваться этими функциями неудобно, они
в первую очередь предназначены для графических сред разработки.
Некоторые из таких сред (включая pgAdmin) имеют встроенный
интерфейс для отладки. Но чтобы им воспользоваться, сначала все
равно придется установить расширение pldbgapi в соответствующую
базу данных.
Исходный код отладчика доступен по ссылке:
6
Служебные сообщения
Не только отладка кода
мониторинг долго выполняющихся процессов
ведение журнала приложения
Подходы к реализации
вывод на консоль или в журнал сервера
запись в таблицу или в файл
передача информации другим процессам
Второй способ отладки предполагает добавление в важные места кода
служебных сообщений, содержащих текущий контекст. Анализируя
сообщения можно понять, что именно пошло не так.
Помимо собственно отладки, служебные сообщения могут выполнять
и другие функции. Сообщения помогут определить, на каком этапе
выполнения находится долго выполняющийся процесс. Приложение
может вести собственный журнал, по аналогии с тем, как СУБД ведет
журнал сообщений сервера. Такой журнал с важной информацией
(например, с данными о запуске отчетов: название отчета, имя
пользователя, дата выполнения, значения параметров и т. д.) может
сильно облегчить работу специалистов поддержки.
Можно выделить несколько подходов к реализации служебных
сообщений в PL/pgSQL. Помимо вывода сообщений на консоль
(а также в журнал сообщений сервера) уже знакомой командой RAISE,
можно отправлять сообщения другому процессу, записывать
сообщения в таблицу или в файл.
При выборе того или иного подхода нужно обращать внимание на
много вопросов. Являются ли сообщения транзакционными
тправляются не дожидаясь окончания транзакции или только при ее
завершении)? Можно ли отправлять сообщения одновременно из
нескольких сеансов? Как организовать доступ к журналу сообщений и
как очищать его от старых записей? Какое влияние оказывают
журналирование на производительность? Требуется ли модификация
исходного кода?
7
Команда RAISE
DEBUG
LOG
NOTICE
INFO
WARNING
RAISE
DEBUG INFO NOTICE WARNING ERROR LOG FATAL PANIC
log_min_messages
Журнал сервера
DEBUG LOG NOTICE WARNING ERROR FATAL PANIC
client_min_messages
Клиент
Мы уже встречались с командой RAISE. Она служит и для вызова
исключительных ситуаций, что подробно рассматривалось в теме «PL/
pgSQL. Обработка ошибок», и для отправки сообщений. Причем
сообщения можно не только отправлять клиенту, но и записывать
в журнал сервера.
В простом случае для отладки нужно добавить вызовы RAISE NOTICE
в код функции, запустить функцию на выполнение (например в сеансе
psql) и проанализировать получаемые по ходу выполнения сообщения.
Сообщения RAISE нетранзакционные: они отправляются асинхронно и
не зависят от статуса завершения транзакции.
Для управления отправкой сообщений используются уровень
сообщения (DEBUG, LOG, NOTICE, INFO, WARNING) и параметры
сервера. От значений параметров зависит, будет ли сообщение
отправлено клиенту (client_min_messages) и/или записано в журнал
сервера (log_min_messages). Сообщение будет отправлено, если
уровень команды RAISE равен значению соответствующего параметра
или больше его (находится правее на рисунке).
Значения параметров по умолчанию настроены так, что сообщения
с уровнем NOTICE отправляются только клиенту, с уровнем LOG —
только в журнал, а с уровнем WARNING — и клиенту, и в журнал.
Сообщения с уровнем INFO всегда отправляются клиенту, их нельзя
перехватить параметром client_min_messages.
9
Процесс→процесс (IPC)
NOTIFY → LISTEN
команды SQL
транзакционное выполнение, неудобно для отладки
Статус сеанса
параметр application_name
виден в представлении pg_stat_activity и выводе команды ps
можно использовать в журнальных сообщениях
Серверные процессы в PostgreSQL могут обмениваться информацией
между собой.
Среди встроенных решений можно отметить следующие.
Использование команд NOTIFY для отправки сообщений в одном
процессе и LISTEN для получения в другом. Но эти команды
являются транзакционными, поэтому они неудобны для отладки:
1. Сообщения отправляются только при фиксации транзакции, а не
сразу после выполнения NOTIFY. Поэтому невозможно следить за
ходом процесса.
2. Если транзакция завершится неуспешно, то сообщения вообще не
будут отправлены.
Использование параметра application_name.
Сеанс с долго выполняющимся процессом может периодически
записывать статус выполнения в application_name. В другом сеансе
администратор может опрашивать представление pg_stat_activity,
содержащем подробную информацию о всех выполняющихся
сеансах. Также значение application_name обычно видно в выводе
команды ps.
Значение application_name также можно записывать в журнал
сервера (настраивая параметр log_line_prefix). Это облегчит поиск
нужных строк в журнале.
11
Процесс→таблица
Расширение dblink
входит в состав сервера
накладные расходы на создание соединения
Автономные транзакции
коммерческий дистрибутив (Postgres Pro Enterprise)
Еще один способ сохранения отладочных сообщений — запись
в таблицу базы данных.
К плюсам данного подхода относится то, что параллельная работа
и доступ журналу обеспечиваются средствами самой СУБД.
Однако нужно позаботиться о том, чтобы вставка в таблицу была
нетранзакционной. Для этого можно использовать расширение dblink,
идущее в составе сервера PostgreSQL. Это расширение позволяет
открыть новое соединение к той же самой базе данных, поэтому
вставка в таблицу выполняется в другой — независимой — транзакции.
К минусам данного подхода относится то, что открытие нового
соединения требует дополнительных ресурсов сервера.
Подробнее работа с dblink рассматривается в курсе DEV2.
В коммерческих дистрибутивах, например Postgres Pro Enterprise,
доступен механизм автономных транзакций, не имеющий таких
существенных накладных расходов, которые характерны для dblink.
13
Процесс→файл
Расширение adminpack
входит в состав сервера
в том числе позволяет записывать текстовые файлы
Недоверенные языки
например, PL/Perl
Вести запись сообщений можно и в файл операционной системы.
Для этого, например, можно использовать расширение adminpack,
которое позволяет записывать данные в любой файл, доступ
к которому есть у пользователя ОС postgres.
Другой вариант — написать функцию на недоверенном языке (таком,
как PL/Perl — plperlu), которая будет выполнять ту же задачу.
Различные языки серверного программирования рассматриваются
в курсе DEV2.
15
Трассировка SQL
Стандартная трассировка в журнал сообщений
накладные расходы на запись в журнал
большой размер файла журнала
требуются инструменты для анализа
нужен доступ к журналу (безопасность)
Настройки
долго выполняющиеся команды log_min_duration_statement
какие команды записывать log_statement
контекст сообщения log_line_prefix
В некоторых случаях может оказаться полезной трассировка всего
происходящего в коде. Штатными средствами можно вывести
в журнал сообщений сервера SQL-запросы сеансов. Надо учитывать:
Высоконагруженное приложение может выполнять огромное число
запросов. Их запись в файл журнала может оказывать влияние на
производительность подсистемы ввода/вывода.
В большинстве случаев требуются специальные инструменты для
анализа такого объема данных. Стандарт де-факто — pgBadger.
К файлу журнала на сервере может не быть доступа у разработчи-
ков приложений. К тому же в журнале промышленной системе могут
оказаться команды, содержащие конфиденциальную информацию.
Для настройки трассировки имеется ряд параметров, основные из
которых приведены на слайде. Полный список:
Не обязательно устанавливать конфигурационные параметры для
всего кластера. Их действие можно ограничить отдельными сеансами
при помощи команд SET, ALTER DATABASE, ALTER ROLE ак
рассказы-валось в темах «Обзор базового инструментария. Установка
и управление, psql» и «Организация данных. Логическая структура»).
16
Трассировка SQL
Расширение auto_explain
запись в журнал планов выполнения запросов
трассировка вложенных запросов
Настройки
планы долгих команд auto_explain.log_min_duration
вложенные запросы auto_explain.log_nested_statements
При включении трассировки SQL-команды попадают в журнал в том
виде, в каком они отправлены на сервер. Если была вызвана
подпрограмма PL/pgSQL, то в журнале будет записан только вызов
этой подпрограммы (например, оператор SELECT или CALL), но не
будет тех команд, которые выполняются внутри подпрограммы.
Чтобы вывести в журнал сообщений запросы не только верхнего
уровня, но и вложенные, потребуется штатное расширение
auto_explain.
Как следует из названия расширения, его основная задача —
записывать в журнал не только текст команды, но и план ее
выполнения. Это тоже может оказаться полезно, хотя относится не
к трассировке как таковой, а к оптимизации запросов (которая
рассматривается в курсе QPT).
17
Трассировка PL/pgSQL
Расширение plpgsql_check
накладные расходы на запись сообщений
большой объем выдачи
Основные настройки
включение трассировки plpgsql_check.enable_tracer
plpgsql_check.tracer
уровень сообщений plpgsql_check.tracer_errlevel
Чтобы разобраться по журналу, какой процедурный код выполнялся,
придется сопоставить SQL-запросы с подпрограммами на PL/pgSQL,
а это может оказаться не просто. Стандартной возможности для
трассировки PL/pgSQL-кода не предусмотрено, но расширение Павла
Стехуле plpgsql_checkоторое упоминалось в теме «PL/pgSQL.
Выполнение запросов») позволяет ее выполнить.
Подобная трассировка вызывает большие накладные расходы и
должна использоваться только для отладки, но не в промышленной
эксплуатации.
19
Итоги
PL/pgSQL Debugger — API отладчика, используется
в графических средах разработки
Служебные сообщения — вывод на консоль, запись
в журнал сообщений сервера, в таблицу или в файл,
передача другим процессам
Возможность трассировки сеансов
20
Практика
1. Измените функцию get_catalog так, чтобы динамически
формируемый текст запроса записывался в журнал
сообщений сервера.
В приложении выполните несколько раз поиск, заполняя
разные поля, и убедитесь, что команды SQL формируются
правильно.
2. Включите трассировку команд SQL на уровне сервера.
Поработайте в приложении и проверьте, какие команды
попадают в журнал сообщений.
Выключите трассировку.
2. Для включения трассировки установите значение параметра
log_min_duration_statement в 0 и перечитайте конфигурацию. В журнал
будут записываться все команды и время их выполнения.
Проще всего это сделать командой ALTER SYSTEM SET. Другие
способы рассматривались в теме «Обзор базового инструментария.
Установка и управление, psql». Не забудьте перечитать
конфигурационный файл.
После просмотра журнала следует вернуть значение параметра
log_min_duration_statement в значение по умолчанию (-1), чтобы
отключить трассировку. Удобный способ — команда ALTER SYSTEM
RESET.
21
Практика
1. Включите трассировку PL/pgSQL-кода средствами
расширения plpgsql_check и проверьте ее работу на
примере нескольких подпрограмм, вызывающих одна
другую.
2. При выводе отладочных сообщений из PL/pgSQL-кода
удобно понимать, к какой подпрограмме они относятся.
В демонстрации имя функции выводилось вручную.
Реализуйте функционал, автоматически добавляющий
к тексту сообщений имя текущей функции или
процедуры.
1. Для включения трассировки загрузите расширение plpgsql_check
в память сеанса командой LOAD, затем установите в сеансе оба
параметра plpgsql_check.enable_tracer и plpgsql_check.tracer в значение
«on».
2. Имя подпрограммы можно получить, разобрав стек вызовов.
Воспользуйтесь результатами практического задания 3 к теме
«Обработка ошибок».