Модуль pg_stat_statements
Модуль pg_stat_statements
предоставляет средства для отслеживания статистики планирования и выполнения всех операторов SQL, выполняемых сервером.
Модуль необходимо загрузить, добавив pg_stat_statements
в shared_preload_libraries в файле postgresql.conf
, поскольку для этого требуется дополнительная общая память. Это означает, что для добавления или удаления модуля необходим перезапуск сервера. Кроме того, для того, чтобы модуль был активен, необходимо включить вычисление идентификатора запроса, что выполняется автоматически, если для параметра calculate_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
.
1. Представление (View) pg_stat_statements
Статистика, собранная модулем, доступна через представление с именем pg_stat_statements
. Это представление содержит по одной строке для каждой отдельной комбинации идентификатора базы данных, идентификатора пользователя, идентификатора запроса и того, является ли это оператором верхнего уровня или нет (до максимального количества отдельных операторов, которые может отслеживать модуль). Столбцы представления показаны в Таблице 1 .
Таблица 1. Столбцы pg_stat_statements
Столбцы | Тип столбца | Описание |
userid | oid(ссылки pg_authid. oid) | OID пользователя, выполнившего оператор |
dbid | oid(ссылки pg_database. oid) | OID базы данных, в которой был выполнен оператор |
toplevel | bool | Истинно, если запрос был выполнен как оператор верхнего уровня (всегда истинно, если pg_stat_statements.track установлено значение top) |
queryid | bigint | Хэш-код для идентификации идентичных нормализованных запросов. |
query | text | Текст заявления представителя |
plans | bigint | Количество запланированных операций (если pg_stat_statements.track_planning включено, иначе ноль) |
total_plan_time | double precision | Общее время, затраченное на планирование выписки, в миллисекундах (если pg_stat_statements.track_planning включено, иначе ноль) |
min_plan_time | double precision | Минимальное время, затраченное на планирование выписки, в миллисекундах (если pg_stat_statements.track_planning включено, иначе ноль) |
max_plan_time | double precision | Максимальное время, затрачиваемое на планирование выписки, в миллисекундах (если pg_stat_statements.track_planning включено, иначе ноль) |
mean_plan_time | double precision | Среднее время, затраченное на планирование выписки, в миллисекундах (если pg_stat_statements.track_planning включено, иначе ноль) |
stddev_plan_time | double precision | Стандартное отклонение совокупности времени, затраченного на планирование оператора, в миллисекундах (если pg_stat_statements.track_planning включено, иначе ноль) |
calls | bigint | Сколько раз оператор был выполнен |
total_exec_time | double precision | Общее время, затраченное на выполнение оператора, в миллисекундах |
min_exec_time | double precision | Минимальное время, затраченное на выполнение оператора, в миллисекундах |
max_exec_time | double precision | Максимальное время, затраченное на выполнение оператора, в миллисекундах |
mean_exec_time | double precision | Среднее время, затрачиваемое на выполнение оператора, в миллисекундах |
stddev_exec_time | double precision | Стандартное отклонение населения времени, затраченного на выполнение оператора, в миллисекундах |
rows | bigint | Общее количество строк, извлеченных или затронутых оператором |
shared_blks_hit | bigint | Общее количество попаданий в общий кэш блоков оператором |
shared_blks_read | bigint | Общее количество общих блоков, прочитанных инструкцией |
shared_blks_dirtied | bigint | Общее количество общих блоков, испорченных оператором |
shared_blks_written | bigint | Общее количество общих блоков, записанных оператором |
local_blks_hit | bigint | Общее количество попаданий в локальный кэш блоков оператором |
local_blks_read | bigint | Общее количество локальных блоков, прочитанных оператором |
local_blks_dirtied | bigint | Общее количество локальных блоков, испорченных оператором |
local_blks_written | bigint | Общее количество локальных блоков, записанных оператором |
temp_blks_read | bigint | Общее количество временных блоков, прочитанных оператором |
temp_blks_written | bigint | Общее количество временных блоков, записанных оператором |
blk_read_time | double precision | Общее время, затраченное оператором на чтение блоков файла данных, в миллисекундах (если включена функция track_io_timing , иначе ноль) |
blk_write_time | double precision | Общее время, затраченное оператором на запись блоков файла данных, в миллисекундах (если включена функция track_io_timing , иначе ноль) |
temp_blk_read_time | double precision | Общее время, затраченное оператором на чтение блоков временного файла, в миллисекундах (если включена функция track_io_timing , иначе ноль) |
temp_blk_write_time | double precision | Общее время, затраченное оператором на запись блоков временного файла, в миллисекундах (если включена функция track_io_timing , иначе ноль) |
wal_records | bigint | Общее количество записей WAL, сгенерированных оператором |
wal_fpi | bigint | Общее количество полностраничных изображений WAL, сгенерированных оператором |
wal_bytes | numeric | Общий объем WAL, сгенерированный оператором, в байтах |
jit_functions | bigint | Общее количество функций, JIT-компилируемых оператором |
jit_generation_time | double precision | Общее время, затрачиваемое оператором на генерацию JIT-кода, в миллисекундах |
jit_inlining_count | bigint | Сколько раз функции были встроены |
jit_inlining_time | double precision | Общее время, затрачиваемое оператором на встраивание функций, в миллисекундах |
jit_optimization_count | bigint | Сколько раз выражение было оптимизировано |
jit_optimization_time | double precision | Общее время, затраченное оператором на оптимизацию, в миллисекундах |
jit_emission_count | bigint | Количество генерируемых кодов |
jit_emission_time | double precision | Общее время, затраченное оператором на генерацию кода, в миллисекундах |
Из соображений безопасности только суперпользователям и ролям с привилегиями роли pg_read_all_stats
разрешено видеть текст SQL и queryid
запросы, выполняемые другими пользователями. Однако другие пользователи могут просматривать статистику, если представление установлено в их базе данных.
Планируемые запросы (то есть , SELECT
, INSERT
, UPDATE
и DELETE
) MERGE
объединяются в одну pg_stat_statements
запись, если они имеют идентичные структуры запросов в соответствии с внутренним вычислением хэша. Обычно для этой цели два запроса считаются одинаковыми, если они семантически эквивалентны, за исключением значений литеральных констант, появляющихся в запросе. Однако служебные команды (то есть все остальные команды) сравниваются строго на основе их текстовых строк запроса.
Примечание
Следующие сведения о постоянной замене queryid
применяются только при включенном параметре calculate_query_id . Если вместо этого вы используете внешний модуль для вычисления queryid
, вам следует обратиться к его документации за подробностями.
Если значение константы было проигнорировано в целях сопоставления запроса с другими запросами, константа заменяется символом параметра, например, $1
на pg_stat_statements
дисплее. Остальной текст запроса — это текст первого запроса, который имел конкретное queryid
хэш-значение, связанное с pg_stat_statements
записью.
В некоторых случаях запросы с явно различающимися текстами могут быть объединены в одну 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
не всегда должны совпадать, поскольку статистика планирования и выполнения обновляется на соответствующей конечной фазе и только для успешных операций. Например, если оператор успешно спланирован, но на этапе выполнения произошел сбой, будет обновлена только его статистика планирования. Если планирование пропущено из-за использования кэшированного плана, будет обновлена только статистика его выполнения.
2. Вид pg_stat_statements_info
Статистика pg_stat_statements
самого модуля отслеживается и становится доступной через представление с именем pg_stat_statements_info
. Это представление содержит только одну строку. Столбцы представления показаны в Таблице 2 .
Таблица 2. pg_stat_statements_info
Столбцы | Тип столбца | Описание |
dealloc | bigint | Общее количество раз, когда pg_stat_statementsзаписи о наименее выполняемых инструкциях были освобождены из-за большего количества различных инструкций, чем pg_stat_statements.max наблюдалось. |
stats_reset | timestamp with time zone | Время pg_stat_statements последнего сброса всей статистики в представлении. |
3. Функции
pg_stat_statements_reset(userid Oid, dbid Oid, queryid bigint) returns void
pg_stat_statements_reset отбрасывает статистику, собранную до сих пор, в соответствии 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.
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, , , и . Значение по умолчанию равно . Только суперпользователи могут изменить этот параметр.INSERTUPDATEDELETEMERGEon
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
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 |