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) и т.д.