F.47. pg_stat_statements — отслеживание статистики планирования и выполнения SQL#
F.47. pg_stat_statements — отслеживание статистики планирования и выполнения SQL #
Модуль 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
.
F.47.1. Представление pg_stat_statements
#
Все статистические данные, собранные модулем, доступны через представление с именем pg_stat_statements
. Это представление содержит одну строку для каждой уникальной комбинации идентификатора базы данных, идентификатора пользователя, идентификатора запроса и указания, является ли он верхнеуровневым оператором или нет (до максимального количества уникальных операторов, которое может отслеживать модуль). Столбцы представления показаны в Таблица F.22.
Таблица F.22. pg_stat_statements
Колонки
Тип столбца Описание |
---|
OID пользователя, выполнившего оператор |
OID базы данных, в которой был выполнен оператор |
True, если запрос был выполнен как самостоятельный оператор (всегда true, если |
Хеш-код для идентификации одинаковых нормализованных запросов. |
Текст представительного заявления |
Количество раз, когда был запланирован оператор
(если |
Суммарное время, затраченное на планирование оператора, в миллисекундах (если |
Минимальное время, затраченное на планирование запроса, в миллисекундах.
Это поле будет равно нулю, если |
Максимальное время, затраченное на планирование запроса, в миллисекундах.
Это поле будет равно нулю, если |
Среднее время, затраченное на планирование оператора, в миллисекундах
(если |
Стандартное отклонение популяции времени, затраченного на планирование оператора,
в миллисекундах
(если |
Количество выполнений оператора: {Number of times the statement was executed |
Общее время выполнения оператора, в миллисекундах |
Минимальное время выполнения оператора в миллисекундах,
это поле будет равно нулю до тех пор, пока этот оператор
не будет выполнен впервые после сброса, выполненного
функцией |
Максимальное время выполнения оператора в миллисекундах,
это поле будет равно нулю до тех пор, пока этот оператор
не будет выполнен впервые после сброса, выполненного
функцией |
Среднее время выполнения оператора, в миллисекундах |
Стандартное отклонение популяции времени выполнения оператора, в миллисекундах |
Общее количество строк, полученных или затронутых оператором |
Общее количество попаданий в кеш общих блоков по оператору |
Общее количество общих блоков, прочитанных оператором |
Общее количество общих блоков, измененных оператором |
Общее количество общих блоков, записанных оператором |
Общее количество локальных попаданий в кеш блоков оператором |
Общее количество локальных блоков, прочитанных оператором |
Общее количество локальных блоков, измененных оператором |
Общее количество локальных блоков, записанных оператором |
Общее количество временных блоков, прочитанных оператором |
Общее количество временных блоков, записанных оператором |
Суммарное время, затраченное на чтение блоков данных из файлов, в миллисекундах (если параметр track_io_timing включен, в противном случае ноль) |
Суммарное время, затраченное на запись блоков файлов данных, в миллисекундах (если включена опция track_io_timing, в противном случае ноль) |
Общее время, затраченное оператором на чтение локальных блоков, в миллисекундах (если track_io_timing включен, иначе ноль) |
Общее время, затраченное оператором на запись локальных блоков, в миллисекундах (если track_io_timing включен, иначе ноль) |
Общее время, затраченное на чтение блоков временных файлов, в миллисекундах (если track_io_timing включено, в противном случае ноль) |
Общее время, затраченное на запись блоков временных файлов, в миллисекундах (если track_io_timing включено, в противном случае ноль) |
Общее количество записей WAL, сгенерированных оператором |
Общее количество полных страниц WAL, сгенерированных оператором |
Общий объем WAL, сгенерированный оператором в байтах |
Общее количество функций, скомпилированных JIT-компилятором в рамках оператора |
Общее время, затраченное оператором на генерацию JIT-кода, в миллисекундах |
Общее количество функций деформации кортежей, скомпилированных JIT для оператора |
Общее время, затраченное оператором на JIT-компиляцию функций деформации кортежей, в миллисекундах |
Время начала сбора статистики для этого оператора |
Время начала сбора статистики min/max для этого
оператора (поля |
Количество раз, когда функции были встроены |
Общее время, затраченное оператором на встраивание функций, в миллисекундах |
Количество раз, когда оператор был оптимизирован |
Общее время, затраченное на оптимизацию запроса, в миллисекундах |
Количество раз, код был выведен |
Общее время, затраченное оператором на генерацию кода, в миллисекундах |
Для обеспечения безопасности, только суперпользователи и роли с привилегиями роли 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
, обсуждаемое ниже
в Раздел F.47.2,
предоставляет статистику об освобождении записей.
В некоторых случаях запросы с явно разным текстом могут быть объединены в одну запись pg_stat_statements
. Обычно это происходит только для семантически эквивалентных запросов, но существует небольшая вероятность коллизий хешей, из-за которых несвязанные запросы могут быть объединены в одну запись. (Однако это не может произойти для запросов, принадлежащих разным пользователям или базам данных).
Так как значение хеша queryid
вычисляется на основе представления запросов после анализа, обратное также возможно: запросы с идентичными текстами могут появляться как отдельные записи, если они имеют различные значения в результате факторов, таких как разные настройки search_path
.
Потребители pg_stat_statements
могут захотеть использовать
queryid
(возможно, в сочетании с
dbid
и userid
) в качестве более стабильного
и надежного идентификатора для каждой записи, чем ее текст запроса.
Однако важно понимать, что существуют только ограниченные
гарантии стабильности хеш-значения queryid
. Поскольку идентификатор производится из
дерева после анализа разбора, его значение является функцией, среди прочего,
внутренних идентификаторов объектов, появляющихся в этом представлении.
Это имеет некоторые контринтуитивные последствия. Например,
pg_stat_statements
будет считать два, на первый взгляд, идентичных
запроса разными, если они ссылается на таблицу, которая была удалена
и воссоздана между выполнением двух запросов.
Процесс хеширования также чувствителен к различиям в
архитектуре машины и другим аспектам платформы.
Кроме того, нельзя считать, что queryid
будет стабильным в разных основных версиях Tantor SE-1C.
Два сервера, участвующие в репликации на основе физического воспроизведения WAL, могут
иметь идентичные значения queryid
для
одного и того же запроса. Однако схемы логической репликации не обещают
сохранять реплики идентичными во всех соответствующих деталях, поэтому
queryid
не будет полезным идентификатором для
накопления затрат по набору логических реплик.
В случае сомнений рекомендуется прямое тестирование.
В общем, можно предположить, что значения queryid
стабильны между минорными версиями Tantor SE-1C, при условии, что экземпляры работают на одной и той же архитектуре машины и детали метаданных каталога совпадают. Совместимость будет нарушена между минорными версиями только в крайнем случае.
Все символы параметров, используемые для замены констант в текстах представительных запросов, начинаются с номера, следующего за наивысшим значением параметра $
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
не всегда ожидаются совпадать, потому что статистика планирования и выполнения обновляется в соответствующей конечной фазе и только для успешных операций. Например, если операция успешно запланирована, но не удалось выполнить во время фазы выполнения, будет обновлена только статистика планирования. Если планирование прне указано из-за использования кешированного плана, будет обновлена только статистика выполнения.
F.47.2. Представление pg_stat_statements_info
#
Статистика модуля pg_stat_statements
отслеживается и доступна через представление с именем pg_stat_statements_info
. Это представление содержит только одну строку. Столбцы представления показаны в Таблица F.23.
Таблица F.23. pg_stat_statements_info
Columns
Тип столбца Описание |
---|
Общее количество раз, когда записи |
Время, когда все статистические данные в представлении |
F.47.3. Функции #
-
pg_stat_statements_reset(userid Oid, dbid Oid, queryid bigint, minmax_only boolean) returns timestamp with time zone
pg_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
. Время последнего выполненного сброса min/max показано в поле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
представления, будет содержать значения null). Эта функция предназначена для поддержки внешних инструментов, которым может потребоваться избежать издержек на повторное получение текстов запросов неопределенной длины. Такие инструменты могут вместо этого кешировать первый обнаруженный текст запроса для каждой записи, поскольку это делает и самpg_stat_statements
, и затем получать тексты запросов только по мере необходимости. Поскольку сервер хранит тексты запросов в файле, такой подход может снизить физический ввод-вывод при повторном изучении данныхpg_stat_statements
.
F.47.4. Параметры конфигурации #
-
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
F.47.5. Пример вывода #
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 |
F.47.6. Авторы #
Takahiro Itagaki <itagaki.takahiro@oss.ntt.co.jp>
.
Нормализация запроса добавлена Питером Геогеганом <peter@2ndquadrant.com>
.