PostgreSQL | Статистика вызовов функций

PostgreSQL | Статистика вызовов функций

Базовая установка PostgreSQL не даёт нам информацию об активности работы наших функций так как мониторинг выключен. Мониторинг требует фиксации данных, а это всегда небольшая дополнительная нагрузка на систему. Зачем нагружать то, что хорошо работает (до поры, до времени). И всё же, как посмотреть/активировать статистику работы своих функций?

Сперва проверяем результат значения конфигурационного параметра «track_functions«.

show track_functions;
show track_functions - PostgreSQL
show track_functions — PostgreSQL

В случае по умолчанию, мы получим значение «none«. Оно говорит нам о том, что сбор статистики по функциям отключён в PostgreSQL. И в этом можно убедиться, если обратиться к системному представлению «pg_stat_user_functions«.

select * from pg_stat_user_functions;

Результатом будет пустая таблица.

empty pg_stat_user_functions - PostgreSQL
empty pg_stat_user_functions — PostgreSQL

Возможные варианты значений параметра «track_functions«:

  • none
  • pl
  • all

Если все функции написаны на языке «plpgsql» (на процедурном языке), то достаточно установить значение «pl«.

Если нужна статистика по всем вызовам функций включая языки «SQL» и «C», то устанавливаем значение «all«.

 

Как работать с параметром «track_functions» в PostgreSQL?

Важно! Тут есть несколько решений для отслеживания (зависит от задачи):

  • Мы следим только за конкретными функциями и в телах этих функций локально меняем параметр «track_functions»
  • Мы устанавливаем параметр «track_functions» только в рамках открытого соединения (вкладки) для клиентских программ на подобии DBeaver.
  • Мы устанавливаем параметр «track_functions» глобально в конфигурационном файле СУБД PostgreSQL

 

Рассмотрим отслеживание конкретной функции и в её теле установим значение «all» для параметра «track_functions«. Вызываем эту команду сразу после блока begin.

set local track_functions = 'all';

После этого должна накопиться статистика по вызовам вложенных функций, чтобы мы смогли увидеть записи в «pg_stat_user_functions«.

pg_stat_user_functions по вложенным вызовам одной функции - PostgreSQL
pg_stat_user_functions по вложенным вызовам одной функции — PostgreSQL

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

В чём плюс такого отслеживания? Мы можем точечно отследить узкие места в работе нашей сложной функции так как будем понимать какая вложенная функция медленнее всего отрабатывает.

Поле «calls» говорит нам о том, сколько раз вызывалась функция с момента отслеживания.

Поле «total_time» говорит нам о том, сколько общего времени было потрачено на выполнение этой функции и всех других функций, вызванных ею, в миллисекундах с момента отслеживания.

Поле «self_time» говорит нам о том, сколько общего времени было потрачено на выполнение самой функции, без учёта других функций, которые были ею вызваны, в миллисекундах с момента отслеживания.

Если поля «total_time» и «self_time» равны, это значит что данные функции не вызывали никого внутри себя — не вызывали другие самописные функции! Это значит, что внутри них есть только базовая логика SQL.

Можно немного дополнить данные системного представления и получить суммарную статистику по вложенным функциям.

select
  *,
  sum(calls) over() as x_calls,
  sum(total_time) over() as x_total_time,
  sum(self_time) over() as x_self_time,
  sum(total_time) over() / sum(calls) over() as x_avg_total_one_call_time_ms,
  sum(self_time) over() / sum(calls) over() as x_avg_self_one_call_time_ms
from pg_stat_user_functions;

Мы добавили средние значения для существующих полей

pg_stat_user_functions - средние значения вложенных вызовов для одной функции - PostgreSQL
pg_stat_user_functions — средние значения вложенных вызовов для одной функции — PostgreSQL

Функция, которую мы отслеживаем, каждый раз вызывает по 6 функций и иногда затрагивает ещё 3 функции. При накопленной статистике мы можем оценить среднее время роботы нашей функции.

На 213449 её вызовов мы суммарно вызвали 1283178 других вложенных вызовов. Общее время составило 268659 миллисекунд (268 секунд).

Итого: наша функция работает в среднем 1,259 миллисекунд (268659 / 213449).

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