pg_stat_statements — отслеживание статистики планирования и выполнения SQL#
Примечание
Эта страница переведена при помощи нейросети GigaChat.
Модуль pg_stat_statements предоставляет средства для отслеживания статистики планирования и выполнения всех SQL-операторов, выполняемых сервером.
Этот модуль должен быть загружен путем добавления pg_stat_statements к shared_preload_libraries в postgresql.conf, поскольку он требует дополнительной общей памяти. Это означает, что для добавления или удаления модуля требуется перезапуск сервера. Кроме того, чтобы модуль был активен, необходимо включить расчет идентификатора запроса, что делается автоматически, если compute_query_id установлен на auto или on, или загружается любой сторонний модуль, который рассчитывает идентификаторы запросов.
Когда pg_stat_statements активен, он отслеживает статистику во всех базах данных сервера. Для доступа и управления этими статистическими данными модуль предоставляет представления pg_stat_statements и pg_stat_statements_info, а также утилитарные функции pg_stat_statements_reset и pg_stat_statements. Они не доступны глобально, но могут быть включены для конкретной базы данных с помощью CREATE EXTENSION pg_stat_statements.
Представление pg_stat_statements#
Статистика, собранная модулем, доступна через представление с именем pg_stat_statements. Это представление содержит одну строку для каждой уникальной комбинации идентификатора базы данных, идентификатора пользователя, идентификатора запроса и того, является ли это верхнеуровневым оператором или нет (до максимального количества различных операторов, которые может отслеживать модуль). Столбцы представления показаны в таблице ниже.
Столбцы pg_stat_statements:
Тип столбца |
Описание |
|---|---|
|
OID пользователя, который выполнил оператор |
|
OID базы данных, в которой был выполнен оператор |
|
Истина, если запрос был выполнен как верхний уровень оператора (всегда истинно, если |
|
Хеш-код для идентификации идентичных нормализованных запросов |
|
Текст представительного утверждения |
|
Количество раз, когда утверждение было запланировано (если |
|
Общее время, затраченное на планирование оператора, в миллисекундах (если |
|
Минимальное время, потраченное на планирование оператора, в миллисекундах. Это поле будет равно нулю, если |
|
Максимальное время, потраченное на планирование оператора, в миллисекундах. Это поле будет равно нулю, если |
|
Среднее время, затраченное на планирование оператора, в миллисекундах (если |
|
Стандартное отклонение населения времени, затраченного на планирование утверждения, в миллисекундах (если |
|
Количество раз, когда было выполнено утверждение |
|
Общее время выполнения оператора, в миллисекундах |
|
Минимальное время выполнения оператора, в миллисекундах. Это поле будет равно нулю до первого выполнения данного оператора после сброса, произведенного функцией |
|
Максимальное время выполнения оператора, в миллисекундах. Это поле будет равно нулю до первого выполнения данного оператора после сброса, произведенного функцией |
|
Среднее время выполнения оператора в миллисекундах |
|
Стандартное отклонение населения времени, затраченного на выполнение оператора, в миллисекундах |
|
Общее количество строк, извлеченных или затронутых оператором |
|
Общее количество попаданий в кеш общих блоков оператором |
|
Общее количество общих блоков, прочитанных оператором |
|
Общее количество общих блоков, поврежденных оператором |
|
Общее количество общих блоков, записанных оператором |
|
Общее количество попаданий локального блока кеша оператором |
|
Общее количество локальных блоков, прочитанных оператором |
|
Общее количество загрязненных локальных блоков оператором |
|
Общее количество локальных блоков, записанных оператором |
|
Общее количество временных блоков, прочитанных оператором |
|
Общее количество временных блоков, записанных оператором |
|
Общее время, потраченное оператором на чтение общих блоков, в миллисекундах (если включена опция |
|
Общее время, потраченное оператором на запись общих блоков, в миллисекундах (если включена опция |
|
Общее время, потраченное оператором на чтение локальных блоков, в миллисекундах (если включена опция |
|
Общее время, потраченное оператором на запись локальных блоков, в миллисекундах (если включена опция |
|
Общее время, которое оператор потратил на чтение временных файловых блоков, в миллисекундах (если |
|
Общее время, которое оператор затратил на запись временных файловых блоков, в миллисекундах (если |
|
Общее количество записей WAL, сгенерированных оператором |
|
Общее количество полных изображений страниц WAL, сгенерированных оператором |
|
Общее количество WAL, сгенерированное оператором в байтах |
|
Общее количество функций, скомпилированных JIT-оператором |
|
Общее время, затраченное оператором на генерацию кода JIT, в миллисекундах |
|
Количество раз, когда функции были встроены |
|
Общее время, затраченное оператором на встраивание функций, в миллисекундах |
|
Количество раз, когда оператор был оптимизирован |
|
Общее время, затраченное оператором на оптимизацию, в миллисекундах |
|
Количество раз, когда код был сгенерирован |
|
Общее время, затраченное оператором на генерацию кода, в миллисекундах |
|
Общее число функций деформации кортежей, компилированных методом JIT для данного оператора |
|
Общее время, затраченное оператором на JIT-компиляцию функций деформации кортежей, в миллисекундах |
|
Время начала сбора статистики по данному оператору |
|
Время начала сбора минимальной/максимальной статистики по этому оператору (поля |
По соображениям безопасности только суперпользователи и роли с привилегиями роли pg_read_all_stats имеют право видеть текст SQL и queryid запросов, выполненных другими пользователями. Однако другие пользователи могут просматривать статистику, если представление было установлено в их базе данных.
Планируемые запросы (то есть, SELECT, INSERT, UPDATE, DELETE и MERGE) и служебные команды объединяются в единую запись pg_stat_statements всякий раз, когда они имеют одинаковую структуру запросов согласно внутреннему расчету хеша. Обычно два запроса считаются одинаковыми для этой цели, если они семантически эквивалентны за исключением значений литеральных констант, встречающихся в запросе. Команды утилиты (то есть все остальные команды) сравниваются строго на основе их текстовых строк запросов.
Примечание
Следующие сведения о замене констант и queryid применяются только при включении compute_query_id. Если используется внешний модуль для вычисления queryid, то следует обратиться к его документации за подробностями.
Когда значение константы было проигнорировано с целью сопоставления запроса другим запросам, константа заменяется символом параметра, таким как $1, в отображении pg_stat_statements. Остальной текст запроса – это первый запрос, который имел конкретное хеш-значение queryid, связанное со входом pg_stat_statements.
Запросы, к которым может применяться нормализация, можно наблюдать со значениями констант в pg_stat_statements, особенно когда наблюдается высокая частота освобождения записей. Чтобы уменьшить вероятность возникновения такой ситуации, рассмотрите возможность увеличения значения pg_stat_statements.max. В представлении pg_stat_statements_info приводится статистика об освобождении записей.
В некоторых случаях запросы с явно разными текстами могут быть объединены в одну запись pg_stat_statements. Обычно это происходит только для семантически эквивалентных запросов, но существует небольшой шанс того, что хеш-коллизии приведут к объединению несвязанных запросов в одну запись. Это невозможно для запросов, принадлежащих разным пользователям или базам данных.
Поскольку значение хеша queryid вычисляется на основе представления запроса после анализа синтаксиса, возможно и обратное: запросы с идентичными текстами могут отображаться как отдельные записи, если они имеют разные значения из-за таких факторов, как различные настройки search_path.
Пользователи pg_stat_statements могут пожелать использовать queryid (возможно, в сочетании с dbid и userid) в качестве более стабильного и надежного идентификатора для каждой записи, чем текст запроса. Однако важно понимать, что существуют лишь ограниченные гарантии стабильности значения хеша queryid. Поскольку идентификатор получен из дерева пост-анализа синтаксического разбора, его значение является функцией, среди прочего, внутренних идентификаторов объектов, появляющихся в этом представлении. Это имеет некоторые неожиданные последствия. Например, pg_stat_statements будет считать два идентичных на первый взгляд запроса различными, если они ссылаются на таблицу, которая была удалена и воссоздана между выполнениями двух запросов. Процесс хеширования также чувствителен к различиям в архитектуре машины и другим аспектам платформы. Кроме того, нельзя предполагать, что queryid будет стабильным при переходе от одной основной версии к другой PostgreSQL .
В качестве общего правила можно предположить, что значения queryid стабильны и сравнимы только до тех пор, пока версия основного сервера и детали метаданных каталога остаются точно такими же. Можно ожидать, что две серверы, участвующие в репликации на основе физического воспроизведения WAL, будут иметь одинаковые значения queryid для одного и того же запроса. Однако схемы логической репликации не обещают поддерживать копии идентичными во всех соответствующих деталях, поэтому queryid не будет полезным идентификатором для накопления затрат по набору логических копий. Если сомневаетесь, рекомендуется прямое тестирование.
Символы параметров, используемые для замены констант в представительных текстах запросов, начинаются с следующего числа после самого высокого параметра $n в исходном тексте запроса или $1, если его не было. Стоит отметить, что в некоторых случаях могут быть скрытые символы параметров, которые влияют на эту нумерацию. Например, PL / pgSQL использует скрытые параметры символов для вставки значений локальных переменных функции в запросы, так что оператор PL / pgSQL , такой как SELECT i + 1 INTO j, имел бы представительный текст вроде SELECT i + $2.
Текст, представляющий запрос, сохраняется во внешнем файле диска и не потребляют общую память. Поэтому даже очень длинные тексты запросов могут храниться успешно. Однако, если накапливается много длинных текстов запросов, внешний файл может стать неприемлемо большим. В качестве метода восстановления, если это произойдет, pg_stat_statements может решить отбросить тексты запросов, при этом все существующие записи в представлении pg_stat_statements будут показывать пустые поля query, хотя статистика, связанная с каждым queryid, сохраняется. Если это произойдет, рассмотрите возможность уменьшения pg_stat_statements.max, чтобы предотвратить повторение.
plans и calls не всегда должны совпадать, потому что планирование и статистические данные выполнения обновляются на соответствующих конечных этапах и только для успешных операций. Например, если оператор успешно спланирован, но терпит неудачу во время фазы выполнения, будут обновлены только его статистические данные планирования. Если планирование пропускается из-за использования кешированного плана, то будут обновляться только его статистические данные выполнения.
Представление pg_stat_statements_info#
Статистика самого модуля pg_stat_statements отслеживается и предоставляется через представление с именем pg_stat_statements_info. Оно содержит только одну строку. Его столбцы показаны в таблице ниже.
Столбцы pg_stat_statements_info:
Тип столбца |
Описание |
|---|---|
|
Общее количество раз, когда записи о наименее выполняемых операторах были освобождены из-за того, что было замечено больше различных операторов, чем |
|
Время, когда все статистики в представлении |
Функции#
pg_stat_statements_reset(userid Oid, dbid Oid, queryid bigint, minmax_only boolean) returns timestamp with time zonepg_stat_statements_resetотбрасывает статистику, собранную до сих порpg_stat_statements, соответствующую указанномуuserid,dbidиqueryid. Если какой-либо из параметров не указан, для каждого из них используется значение по умолчанию0(недействительно), а статистика, соответствующая другим параметрам, будет сброшена. Если ни один параметр не указан или все указанные параметры являются0(недействительными), это приведет к сбросу всей статистики. Если вся статистика во представленииpg_stat_statementsбыла отброшена, она также сбросит статистику во представленииpg_stat_statements_info. Когдаminmax_onlyустановлено вtrue, будут сброшены только значения минимального и максимального времени планирования и выполнения (то есть поляmin_plan_time,max_plan_time,min_exec_timeиmax_exec_time). Значение параметраminmax_onlyпо умолчанию —false. Время последнего выполненного сброса мин/макс отображается в полеminmax_stats_sinceпредставленияpg_stat_statements. Эта функция возвращает время сброса. Это время сохраняется в полеstats_resetпредставленияpg_stat_statements_infoили в полеminmax_stats_sinceпредставленияpg_stat_statements, если соответствующий сброс был фактически выполнен. По умолчанию эта функция может выполняться только суперпользователями. Доступ можно предоставить другим пользователям с помощьюGRANT.pg_stat_statements(showtext boolean) returns setof recordПредставление
pg_stat_statementsопределено в терминах функции с тем же именемpg_stat_statements. Клиенты могут вызывать функциюpg_stat_statementsнепосредственно, а указавshowtext := false, можно опустить текст запроса (т.е. аргументOUT, соответствующий столбцуqueryпредставления, вернет нулевые значения). Эта функция предназначена для поддержки внешних инструментов, которые могут захотеть избежать накладных расходов при повторяющемся извлечении текстов запросов неопределенной длины. Такие инструменты могут вместо этого кешировать первый текст запроса, наблюдаемый для каждой записи, поскольку это все, что делает самpg_stat_statements, а затем извлекать тексты запросов по мере необходимости. Поскольку сервер хранит тексты запросов в файле, этот подход может уменьшить физический ввод-вывод для повторного анализа данныхpg_stat_statements.
Параметры конфигурации#
pg_stat_statements.max(integer)pg_stat_statements.max– это максимальное количество операторов, отслеживаемых модулем (т.е. максимальное количество строк в представленииpg_stat_statements). Если наблюдается больше различных операторов, чем указано выше, информация о наименее выполняемых операторах удаляется. Количество раз, когда такая информация была отброшена, можно увидеть в представленииpg_stat_statements_info. Значение по умолчанию равно 5000. Этот параметр может быть установлен только при запуске сервера.pg_stat_statements.track(enum)pg_stat_statements.trackконтролирует, какие операторы учитываются модулем. Укажитеtop, чтобы отслеживать основные операторы (те, которые непосредственно выдаются клиентами),all, чтобы также отслеживать вложенные операторы (такие как операторы, вызываемые внутри функций), илиnone, чтобы отключить сбор статистики операторов. Значение по умолчанию –top. Только суперпользователи могут изменить этот параметр.pg_stat_statements.track_utility(boolean)pg_stat_statements.track_utilityуправляет тем, отслеживаются ли утилиты командами модуля. Утилитные команды - все те, кромеSELECT,INSERT,UPDATE,DELETEиMERGE. Значение по умолчанию -on. Только суперпользователи могут изменить этот параметр.pg_stat_statements.track_planning(boolean)pg_stat_statements.track_planningопределяет, отслеживаются ли операции планирования и их продолжительность модулем. Включение этого параметра может привести к заметному снижению производительности, особенно когда операторы с идентичной структурой запроса выполняются многими одновременными соединениями, которые конкурируют за обновление небольшого количества записейpg_stat_statements. Значение по умолчанию равноoff. Только суперпользователи могут изменить этот параметр.pg_stat_statements.save(boolean)pg_stat_statements.saveуказывает, следует ли сохранять статистику операторов при выключении сервера. Если установлено значениеoff, то статистика не сохраняется при завершении работы и не загружается при запуске сервера. Значение по умолчанию равноon. Этот параметр можно задать только в файлеpostgresql.confили в командной строке сервера.
Модуль требует дополнительной общей памяти, пропорциональной pg_stat_statements.max. Обратите внимание, что эта память потребляется всякий раз, когда модуль загружен, даже если pg_stat_statements.track установлен на none.
Эти параметры должны быть установлены в postgresql.conf. Типичное использование может выглядеть так:
# postgresql.conf
shared_preload_libraries = 'pg_stat_statements'
compute_query_id = on
pg_stat_statements.max = 10000
pg_stat_statements.track = all
Пример вывода#
bench=# SELECT pg_stat_statements_reset();
$ pgbench -i bench
$ pgbench -c10 -t300 bench
bench=# \x
bench=# SELECT query, calls, total_exec_time, rows, 100.0 * shared_blks_hit /
nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent
FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 5;
-[ RECORD 1 ]---+--------------------------------------------------------------------
query | UPDATE pgbench_branches SET bbalance = bbalance + $1 WHERE bid = $2
calls | 3000
total_exec_time | 25565.855387
rows | 3000
hit_percent | 100.0000000000000000
-[ RECORD 2 ]---+--------------------------------------------------------------------
query | UPDATE pgbench_tellers SET tbalance = tbalance + $1 WHERE tid = $2
calls | 3000
total_exec_time | 20756.669379
rows | 3000
hit_percent | 100.0000000000000000
-[ RECORD 3 ]---+--------------------------------------------------------------------
query | copy pgbench_accounts from stdin
calls | 1
total_exec_time | 291.865911
rows | 100000
hit_percent | 100.0000000000000000
-[ RECORD 4 ]---+--------------------------------------------------------------------
query | UPDATE pgbench_accounts SET abalance = abalance + $1 WHERE aid = $2
calls | 3000
total_exec_time | 271.232977
rows | 3000
hit_percent | 98.8454011741682975
-[ RECORD 5 ]---+--------------------------------------------------------------------
query | alter table pgbench_accounts add primary key (aid)
calls | 1
total_exec_time | 160.588563
rows | 0
hit_percent | 100.0000000000000000
bench=# SELECT pg_stat_statements_reset(0,0,s.queryid) FROM pg_stat_statements AS s
WHERE s.query = 'UPDATE pgbench_branches SET bbalance = bbalance + $1 WHERE bid = $2';
bench=# SELECT query, calls, total_exec_time, rows, 100.0 * shared_blks_hit /
nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent
FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 5;
-[ RECORD 1 ]---+--------------------------------------------------------------------
query | UPDATE pgbench_tellers SET tbalance = tbalance + $1 WHERE tid = $2
calls | 3000
total_exec_time | 20756.669379
rows | 3000
hit_percent | 100.0000000000000000
-[ RECORD 2 ]---+--------------------------------------------------------------------
query | copy pgbench_accounts from stdin
calls | 1
total_exec_time | 291.865911
rows | 100000
hit_percent | 100.0000000000000000
-[ RECORD 3 ]---+--------------------------------------------------------------------
query | UPDATE pgbench_accounts SET abalance = abalance + $1 WHERE aid = $2
calls | 3000
total_exec_time | 271.232977
rows | 3000
hit_percent | 98.8454011741682975
-[ RECORD 4 ]---+--------------------------------------------------------------------
query | alter table pgbench_accounts add primary key (aid)
calls | 1
total_exec_time | 160.588563
rows | 0
hit_percent | 100.0000000000000000
-[ RECORD 5 ]---+--------------------------------------------------------------------
query | vacuum analyze pgbench_accounts
calls | 1
total_exec_time | 136.448116
rows | 0
hit_percent | 99.9201915403032721
bench=# SELECT pg_stat_statements_reset(0,0,0);
bench=# SELECT query, calls, total_exec_time, rows, 100.0 * shared_blks_hit /
nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent
FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 5;
-[ RECORD 1 ]---+-----------------------------------------------------------------------------
query | SELECT pg_stat_statements_reset(0,0,0)
calls | 1
total_exec_time | 0.189497
rows | 1
hit_percent |
-[ RECORD 2 ]---+-----------------------------------------------------------------------------
query | SELECT query, calls, total_exec_time, rows, $1 * shared_blks_hit / +
| nullif(shared_blks_hit + shared_blks_read, $2) AS hit_percent+
| FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT $3
calls | 0
total_exec_time | 0
rows | 0
hit_percent |