F.52. pg_query_id#
F.52. pg_query_id #
Расширение для управления аспектами вычисления идентификатора запроса.
F.52.1. О pg_query_id #
Версия: 1.0.0
F.52.2. Начало работы #
Предостережение
Расширение должно быть последним в
shared_preload_libraries
или, по крайней мере, последним
расширением, которое использует идентификатор запроса. Проверка на это отсутствует, поэтому будьте
осторожны.
Установите расширение, добавив его в
shared_preload_libraries
и установите GUC для игнорирования
массивов констант. А также добавьте
pg_stat_statements
для дальнейшей проверки.
shared_preload_libraries = 'pg_query_id' pg_query_id.ignore_array_of_constants = on
Запустите БД и выполните эти 2 запроса:
SELECT * FROM generate_series(1, 100) x WHERE x IN (101, 102, 103); SELECT * FROM generate_series(1, 100) x WHERE x IN (101, 102, 103, 104, 105);
pg_stat_statements
должен содержать один запрос
только с 3 константами (другие запросы опущены):
SELECT query FROM pg_stat_statements; query ----------------------------------------------------------------- SELECT * FROM generate_series($1, $2) x WHERE x IN ($3, $4, $5)
F.52.3. Функциональность #
Примечание
Для проверки идентификатора запроса мы используем
pg_stat_statements
в примерах
Чтобы изменить конфигурацию ниже, измените файлы конфигурации и затем отправьте SIGHUP.
F.52.3.1. Включение/отключение #
GUC | По умолчанию |
---|---|
pg_query_id.enabled
|
on
|
Этот параметр управляет тем, запущено ли расширение. С его помощью вы можете отключить расширение во время выполнения, но учтите, что вычисленные идентификаторы запросов будут отличаться.
F.52.3.2. Игнорирование имен временных таблиц #
GUC | По умолчанию |
---|---|
pg_query_id.ignore_temp_tables
|
off
|
Если этот параметр установлен в on
, то OID временных
таблиц не используются при вычислении идентификатора запроса. Это приводит к
одинаковым идентификаторам запросов для запросов, где различаются только временные таблицы,
но остальная часть запроса остается неизменной.
Пример:
CREATE TEMP TABLE temp_tbl1(id int, str text); CREATE TEMP TABLE temp_tbl2(id int, str text); SELECT * FROM temp_tbl1 WHERE id = 1; SELECT * FROM temp_tbl2 WHERE id = 1; SELECT query FROM pg_stat_statements; query ----------------------------------------------- CREATE TEMP TABLE temp_tbl1(id int, str text) SELECT * FROM temp_tbl1 WHERE id = $1
Как вы можете видеть, только первый выполненный запрос был записан, а второй выполненный запрос (с другим именем таблицы) имеет тот же идентификатор запроса, поэтому попадает в ту же кортеж.
F.52.3.3. Игнорировать массивы констант #
GUC | По умолчанию |
---|---|
pg_query_id.ignore_constant_arrays
|
off
|
Если этот параметр установлен в on
, то массивы, состоящие только из
констант (в разных запросах с разной длиной массива),
не будут влиять на вычисление идентификатора запроса. Это включает:
ARRAY[]
VALUES ()
(если каждая строка содержит только константы)IN ()
Если такая конструкция содержит CONSTANTs или IMPLICIT CASTs OF
CONSTANT, то она будет проигнорирована. Т.е. если у вас есть
SELECT 1
внутри массива, это НЕ будет проигнорировано
и будет вычислено по умолчанию.
Пример:
SELECT * FROM generate_series(1, 10) x WHERE x IN (11, 12, 13); SELECT * FROM generate_series(1, 10) x WHERE x IN (11, 12, 13, 14, 15); SELECT * FROM generate_series(1, 10) x WHERE x = ANY(VALUES (11), (12), (13)); SELECT * FROM generate_series(1, 10) x WHERE x = ANY(VALUES (11), (12), (13), (14), (15)); SELECT * FROM generate_series(1, 10) x WHERE x = ALL(ARRAY[11, 12, 13]); SELECT * FROM generate_series(1, 10) x WHERE x = ALL(ARRAY[11, 12, 13, 14, 15]); SELECT query FROM pg_stat_statements; query -------------------------------------------------------------------------------------------- SELECT * FROM generate_series($1, $2) x WHERE x = ALL(ARRAY[$3, $4, $5]) SELECT * FROM generate_series($1, $2) x WHERE x = ANY(VALUES ($3), ($4), ($5)) SELECT * FROM generate_series($1, $2) x WHERE x IN ($3, $4, $5)
Но работают не только константы, но и неявное приведение:
CREATE TABLE tbl(id int, str char(20)); SELECT * FROM tbl WHERE str IN ('a', 'b', 'c'); SELECT * FROM tbl WHERE str IN ('a', 'b', 'c', 'd', 'e'); SELECT query FROM pg_stat_statements; query --------------------------------------------- SELECT * FROM tbl WHERE str IN ($1, $2, $3) CREATE TABLE tbl(id int, str char(20))
Но это НЕ сработает:
SELECT * FROM generate_series(1, 10) x WHERE x IN (11, 12, (SELECT 13)); SELECT * FROM generate_series(1, 10) x WHERE x IN (11, 12, 13, (SELECT 14)); SELECT * FROM generate_series(1, 10) x WHERE x = ANY(VALUES (11), (12), ((SELECT 13))); SELECT * FROM generate_series(1, 10) x WHERE x = ANY(VALUES (11), (12), (13), ((SELECT 14))); SELECT * FROM generate_series(1, 10) x WHERE x = ALL(ARRAY[11, 12, (SELECT 13)]); SELECT * FROM generate_series(1, 10) x WHERE x = ALL(ARRAY[11, 12, 13, (SELECT 14)]); SELECT query FROM pg_stat_statements; query ----------------------------------------------------------------------------------------------- SELECT * FROM generate_series($1, $2) x WHERE x IN ($3, $4, (SELECT $5)) SELECT * FROM generate_series($1, $2) x WHERE x IN ($3, $4, $5, (SELECT $6)) SELECT * FROM generate_series($1, $2) x WHERE x = ALL(ARRAY[$3, $4, (SELECT $5)]) SELECT * FROM generate_series($1, $2) x WHERE x = ALL(ARRAY[$3, $4, $5, (SELECT $6)]) SELECT * FROM generate_series($1, $2) x WHERE x = ANY(VALUES ($3), ($4), ((SELECT $5))) SELECT * FROM generate_series($1, $2) x WHERE x = ANY(VALUES ($3), ($4), ($5), ((SELECT $6)))
F.52.3.4. Постоянный идентификатор запроса для служебных операторов #
GUC | По умолчанию |
---|---|
pg_query_id.utility_constant_query_id
|
off
|
Если этот параметр установлен в on
, то идентификатор запроса для некоторых
типов служебных операторов назначается с предопределенной
константой. Таблица назначения идентификаторов запросов:
Утилита | Идентификатор запроса |
---|---|
СОЗДАТЬ ТАБЛИЦУ
| 1 |
СОЗДАТЬ ВРЕМЕННУЮ ТАБЛИЦУ
| 2 |
CREATE TABLE ... AS
| 3 |
CREATE TEMP TABLE ... AS
| 4 |
СОЗДАТЬ ИНДЕКС
| 5 |
CREATE INDEX (временная таблица)
| 6 |
VACUUM
| 7 |
ОБРЕЗАТЬ
| 8 |
DROP TABLE
| 9 |
DROP INDEX
| 10 |
COPY FROM ... (временная таблица)
| 11 |
COPY FROM ...
| 12 |
COPY TO ... (временная таблица)
| 13 |
COPY TO ...
| 14 |
Эта функциональность может быть полезна для сбора статистики с грубой детализацией, когда мы хотим измерить накладные расходы нескольких DML.
Пример:
CREATE TABLE tbl1(id int); CREATE TABLE tbl2(id int, str text); CREATE TEMP TABLE temp_tbl1(id int); CREATE TEMP TABLE temp_tbl2(id int, str text); CREATE TABLE tbl3 AS SELECT x FROM generate_series(1, 10) x; CREATE TABLE tbl4 AS SELECT x, x::text y FROM generate_series(1, 10) x; CREATE TEMP TABLE temp_tbl3 AS SELECT x FROM generate_series(1, 10) x; CREATE TEMP TABLE temp_tbl4 AS SELECT x, x::text y FROM generate_series(1, 10) x; CREATE INDEX tbl1_id_idx ON tbl1(id); CREATE INDEX temp_tbl1_id_idx ON temp_tbl1(id); VACUUM tbl1; VACUUM temp_tbl1; COPY tbl1 TO STDOUT; COPY tbl2 TO STDOUT; COPY tbl3 TO STDOUT; COPY tbl4 TO STDOUT; COPY temp_tbl1 TO STDOUT; COPY temp_tbl2 TO STDOUT; COPY temp_tbl3 TO STDOUT; COPY temp_tbl4 TO STDOUT; COPY tbl1 FROM STDIN; COPY tbl2 FROM STDIN; COPY tbl3 FROM STDIN; COPY tbl4 FROM STDIN; COPY temp_tbl1 FROM STDIN; COPY temp_tbl2 FROM STDIN; COPY temp_tbl3 FROM STDIN; COPY temp_tbl4 FROM STDIN; TRUNCATE tbl1; TRUNCATE temp_tbl1; DROP INDEX tbl1_id_idx; DROP TABLE tbl1; DROP TABLE tbl2; DROP TABLE tbl3; DROP TABLE tbl4; DROP TABLE temp_tbl1; DROP TABLE temp_tbl2; DROP TABLE temp_tbl3; DROP TABLE temp_tbl4; SELECT queryid, query FROM pg_stat_statements ORDER BY queryid; queryid | query ---------------------+------------------------------------------------------------------------ 1 | CREATE TABLE tbl1(id int) 2 | CREATE TEMP TABLE temp_tbl1(id int) 3 | CREATE TABLE tbl3 AS SELECT x FROM generate_series($1, $2) x 4 | CREATE TEMP TABLE temp_tbl3 AS SELECT x FROM generate_series($1, $2) x 5 | CREATE INDEX tbl1_id_idx ON tbl1(id) 6 | CREATE INDEX temp_tbl1_id_idx ON temp_tbl1(id) 7 | VACUUM tbl1 8 | TRUNCATE tbl1 9 | DROP TABLE tbl1 10 | DROP INDEX tbl1_id_idx 11 | COPY temp_tbl1 FROM STDIN 12 | COPY tbl1 FROM STDIN 13 | COPY temp_tbl1 TO STDOUT 14 | COPY tbl1 TO STDOUT
F.52.4. Известные проблемы #
F.52.4.1. Массив с одним элементом #
Если pg_query_id.ignore_constant_arrays
установлен
и массив содержит один элемент, он автоматически преобразуется в
бинарный оператор или другую форму узла дерева выражений. Например: WHERE a IN (1)
при разборе
преобразуется в WHERE a = 1
.
В настоящее время мы не можем отслеживать такие ситуации, поэтому для таких запросов у нас будет 2 идентификатора запроса: для одного элемента и для нескольких элементов. Т.е. для WHERE a IN (1)
и для WHERE a IN (1, 2)
, WHERE a IN (1, 2, 3)
и т.д.