sr_plan
Описание
Модуль sr_plan позволяет пользователю сохранять планы выполнения и использовать их для последующих выполнений таких же запросов, тем самым предотвращая повторную оптимизацию идентичных запросов.
sr_plan похож на систему Oracle Outline. Данный модуль можно использовать для блокировки плана выполнения. Это может помочь, если есть сомнения в планировщике или невозможно составить лучший план.
Установка
Модуль управления хранением планов запросов в QHB для QHB поставляется в виде пакета qhb-1.5.2-sr-plan.
Подключите репозиторий пакетов QHB и установите пакет расширения для выбранной платформы со страницы загрузки.
Чтобы включить расширение sr_plan, выполните следующие шаги:
- Добавьте имя его библиотеки в переменную shared_preload_libraries в файле qhb.conf:
shared_preload_libraries = 'sr_plan'
Обратите внимание, что имена библиотек в переменной shared_preload_libraries должны идти в особом порядке; информацию о совместимости sr_plan с другими расширениями см. в параграфе Совместимость с другими расширениями.
-
Перезагрузите сервер баз данных, чтобы изменения вступили в силу.
Чтобы убедиться, что библиотека sr_plan установилась корректно, можно выполнить следующую команду:
SHOW shared_preload_libraries;
- Создайте расширение sr_plan с помощью следующего запроса:
CREATE EXTENSION sr_plan;
Важно, чтобы библиотека загружалась заранее, при запуске сервера, поскольку у sr_plan имеется кеш разделяемой памяти, которую можно инициализировать только во время запуска. Расширение sr_plan должно быть создано в каждой базе данных, где требуется управление запросами.
-
Включите расширение sr_plan (по умолчанию оно выключено) одним из следующих способов:
-
Чтобы включить sr_plan для всех обслуживающих процессов, установите sr_plan.enable = true в файле qhb.conf.
-
Чтобы активировать sr_plan в текущем сеансе, выполните следующую команду:
-
SET sr_plan.enable TO true;
- Если вы хотите перенести данные sr_plan с основного на резервный сервер, используя физическую репликацию, установите в параметре sr_plan.wal_rw значение on на обоих серверах. В этом случае убедитесь, что на основном и резервном серверах установлена одна версия sr_plan, иначе нет гарантии, что поток репликации будет корректным.
Применение
Если требуется сохранить план запроса, то необходимо установить следующую переменную:
SET sr_plan.write_mode = true;
Теперь планы для всех последующих запросов будут сохраняться в таблице sr_plans. Обратите внимание, что при этом будут сохранены все запросы, включая дубликаты.
Формирование примера запроса:
SELECT query_hash FROM sr_plans WHERE query_hash=10;
Отключение сохранения плана для запроса:
SET sr_plan.write_mode = false;
Включение сохранения:
UPDATE sr_plans SET enable=true;
После этого план запроса будет браться из таблицы sr_plans.
Таблица sr_plans содержит столбцы query_id, которые можно использовать для соединений с таблицами и представлениями pg_stat_statements.
Кроме того, модуль sr_plan позволяет сохранять параметризованный план запроса. При этом некоторые константы в запросе не существенны. Для параметров используется специальная функция _p (anyelement), например:
SELECT query_hash FROM sr_plans WHERE query_hash=1000+_p(10);
Если сохранить план для запроса, то можно разрешить его использование для последующих запросов:
SELECT query_hash FROM sr_plans WHERE query_hash=1000+_p(11);
SELECT query_hash FROM sr_plans WHERE query_hash=1000+_p(-5);
С помощью функции show_plan можно просмотреть сохраненные планы. Это требует знания хеша запроса, который можно получить из таблицы sr_plans.
Примеры:
Показать включенный план для хеша запроса:
SELECT show_plan(1);
show_plan
----------------------------------------------
("Seq Scan on public.explain_test")
(" Output: test_attr1, test_attr2")
(" Filter: (explain_test.test_attr1 = 10)")
(3 rows)
Получить второй сохраненный план, используя параметр index (игнорирует атрибут enable):
SELECT show_plan(1, index := 2);
show_plan
----------------------------------------------
("Seq Scan on public.explain_test")
(" Output: test_attr1, test_attr2")
(" Filter: (explain_test.test_attr1 = 10)")
(3 rows)
Использовать другой формат вывода (поддерживаются форматы json, text, xml, yaml):
SELECT show_plan(1, format := 'json');
show_plan
------------------------------------------------------
("[ +
{ +
""Plan"": { +
""Node Type"": ""Seq Scan"", +
""Parallel Aware"": false, +
""Relation Name"": ""explain_test"", +
""Schema"": ""public"", +
""Alias"": ""explain_test"", +
""Output"": [""test_attr1"", ""test_attr2""], +
""Filter"": ""(explain_test.test_attr1 = 10)""+
} +
} +
]")
(1 row)
Модуль sr_plan позволяет замораживать планы для дальнейшего использования. Замораживание состоит из трех этапов:
-
Регистрация запроса, для которого нужно заморозить план.
-
Модификация плана выполнения запроса.
-
Заморозка плана выполнения запроса.
Регистрация запроса
Существует два способа зарегистрировать запрос:
- Вызвать функцию sr_register_query():
SELECT sr_register_query(query_string, parameter_type, ...);
Здесь query_string — это ваш запрос с параметрами $n (так же, как в команде PREPARE statement_name AS). Можно описать тип каждого параметра с помощью необязательного аргумента функции parameter_type или предпочесть не определять типы параметров явно. В последнем случае QHB пытается выяснить тип каждого параметра, исходя из контекста. Эта функция возвращает уникальную пару sql_hash and const_hash. Теперь sr_plan будет отслеживать выполнения запросов, соответствующих сохраненному шаблону параметризованного запроса.
-- Создание таблицы 'a'
CREATE TABLE a AS (SELECT * FROM generate_series(1,30) AS x);
CREATE INDEX ON a(x);
ANALYZE;
-- Регистрация запроса
SELECT sql_hash, const_hash
FROM sr_register_query('SELECT count(*) FROM a
WHERE x = 1 OR (x > $2 AND x < $1) OR x = $1', 'int', 'int')
sql_hash | const_hash
----------------------+------------
5393873830515778388 | 15498345
(1 row)
- Воспользоваться параметром sr_plan.auto_tracking:
-- Установка в sr_plan.auto_tracking значения on
SET sr_plan.auto_tracking = on;
-- Выполнение EXPLAIN для непараметризованного запроса
EXPLAIN SELECT count(*) FROM a WHERE x = 1 OR (x > 11 AND x < 22) OR x = 22;
Custom Scan (SRScan) (cost=1.60..0.00 rows=1 width=8)
Plan is: tracked
SQL hash: 5393873830515778388
Const hash: 0
-> Aggregate (cost=1.60..1.61 rows=1 width=8)
-> Seq Scan on a (cost=0.00..1.60 rows=2 width=0)
Filter: ((x = $1) OR ((x > $2) AND (x < $3)) OR (x = $4))
Модификация плана выполнения запроса
План выполнения запроса можно модифицировать с помощью переменных оптимизатора, подсказок pg_hint_plan (если это расширение включено) или других расширений, позволяющих менять план запроса. Информацию о совместимости sr_plan с другими расширениями см. в параграфе Совместимость с другими расширениями.
Замораживание плана выполнения запроса
Для заморозки модифицированного плана запроса воспользуйтесь функцией sr_plan_freeze. В необязательном параметре тип_плана можно установить serialized или hintset. Значение по умолчанию — serialized. Подробную информацию о типах замороженных планов см. в параграфе Типы замороженных планов.
Пример использования
Приведенный ниже пример иллюстрирует применение модуля sr_plan.
-- Регистрация запроса
SELECT sql_hash, const_hash
FROM sr_register_query('SELECT count(*) FROM a
WHERE x = 1 OR (x > $2 AND x < $1) OR x = $1', 'int', 'int')
sql_hash | const_hash
----------------------+------------
5393873830515778388 | 15498345
(1 row)
-- Модификация плана выполнения запроса
SET enable_seqscan = 'off';
Custom Scan (SRScan) (actual rows=1 loops=1)
Plan is: tracked
SQL hash: 5393873830515778388
Const hash: 15498345
-> Aggregate (actual rows=1 loops=1)
-> Index Only Scan using a_x_idx2 on a (actual rows=10 loops=1)
Filter: ((x = 1) OR ((x > $2) AND (x < $1)) OR (x = $1))
Rows Removed by Filter: 20
Heap Fetches: 30
(5 rows)
-- Заморозка плана выполнения запроса
SELECT sr_plan_freeze();
RESET enable_seqscan;
Типы замороженных планов
Существует два типа замороженных планов: сериализованные и с набором подсказок.
-
План serialized — это сериализованное представление плана. Этот план преобразуется в выполняемый план при первом подборе соответствующего замороженного запроса. Сериализованный план остается действительным, пока остаются неизменными метаданные запроса (структуры таблиц, индексы и т. д.). Например, если пересоздается имеющаяся в замороженном плане таблица, этот план становится недействительным и игнорируется. Сериализованный план действителен только в пределах текущей базы данных, и его нельзя скопировать в другую базу, поскольку он зависит от OID. По этой причине непрактично использовать сериализованный план для временных таблиц.
-
План hintset — это набор подсказок, формирующихся на основе плана выполнения при замораживании. Этот набор подсказок состоит из значений переменных среды оптимизатора, отличающихся от установленных по умолчанию, типов соединений, порядка соединений и методов доступа к данным. Эти подсказки соответствуют подсказкам, которые поддерживаются расширением pg_hint_plan. Для использования планов с набором подсказок модуль pg_hint_plan должен быть включен. Набор подсказок передается планировщику pg_hint_plan при первом подборе соответствующего замороженного плана, и pg_hint_plan генерирует выполняемый план. Если расширение pg_hint_plan неактивно, подсказки игнорируются и выполняется план, сгенерированный оптимизатором QHB. Планы с набором подсказок не зависят от идентификаторов объектов и остаются действительными при пересоздании таблиц, добавлении полей и т. д.
Совместимость с другими расширениями
Чтобы гарантировать совместимость sr_plan с другими включенными расширениями, нужно указать имена библиотек в переменной shared_preload_libraries в файле qhb.conf в определенном порядке:
- pg_hint_plan: расширение sr_plan должно быть загружено после pg_hint_plan.
shared_preload_libraries = 'pg_hint_plan, sr_plan'
- pg_stat_statements: расширение sr_plan должно быть загружено перед pg_stat_statements.
shared_preload_libraries = 'sr_plan, pg_stat_statements'
Идентификация замороженных запросов
Замороженный запрос в текущей базе данных идентифицируется по комбинации sql_hash и const_hash.
sql_hash — это хеш, сгенерированный на основе дерева разбора, игнорируя параметры и константы. При этом псевдонимы полей и таблиц не игнорируются. Таким образом, один и тот же запрос, но с разными псевдонимами будет иметь разные значения sql_hash.
const_hash — это хеш, сгенерированный на основе всех имеющихся в запросе констант. Константы с одинаковым значением, но разными типами, например 1 и '1', выдадут разные значения хеша.
Автоматическое приведение типов
Расширение sr_plan автоматически пытается приводить типы констант, имеющихся в запросе, к типам параметров замороженного запроса. Если привести типы невозможно, этот замороженный план игнорируется.
SELECT sql_hash, const_hash
FROM sr_register_query('SELECT count(*) FROM a
WHERE x = $1', 'int');
-- Приведение типов возможно
EXPLAIN SELECT count(*) FROM a WHERE x = '1';
QUERY PLAN
-------------------------------------------------------------
Custom Scan (SRScan) (cost=1.38..0.00 rows=1 width=8)
Plan is: tracked
SQL hash: -5166001356546372387
Const hash: 0
-> Aggregate (cost=1.38..1.39 rows=1 width=8)
-> Seq Scan on a (cost=0.00..1.38 rows=1 width=0)
Filter: (x = $1)
-- Приведение типов возможно
EXPLAIN SELECT count(*) FROM a WHERE x = 1::bigint;
QUERY PLAN
-------------------------------------------------------------
Custom Scan (SRScan) (cost=1.38..0.00 rows=1 width=8)
Plan is: tracked
SQL hash: -5166001356546372387
Const hash: 0
-> Aggregate (cost=1.38..1.39 rows=1 width=8)
-> Seq Scan on a (cost=0.00..1.38 rows=1 width=0)
Filter: (x = $1)
-- Приведение типов невозможно
EXPLAIN SELECT count(*) FROM a WHERE x = 1111111111111;
QUERY PLAN
-------------------------------------------------------
Aggregate (cost=1.38..1.39 rows=1 width=8)
-> Seq Scan on a (cost=0.00..1.38 rows=1 width=0)
Filter: (x = '1111111111111'::bigint)
Представления
Представление sr_plan_storage
Представление sr_plan_storage предоставляет подробную информацию обо всех замороженных операторах. Столбцы этого представления описаны в Таблице 3.
Таблица 3. Столбцы sr_plan_storage
| Столбец Тип | Описание |
|---|---|
| dbid oid | Идентификатор базы данных, в которой выполняется оператор |
| sql_hash bigint | Внутренний идентификатор запроса |
| const_hash bigint | Хеш непараметризованных констант |
| valid boolean | false, если при последнем использовании план был признан недействительным |
| query_string text | Запрос, зарегистрированный функцией sr_register_query |
| paramtypes regtype[] | Массив с типами параметров, использованных в запросе |
| query text | Внутреннее представление запроса |
| plan text | Внутреннее представление плана |
| hintstr text | Набор подсказок, сформированный на основе замороженного плана |
Представление sr_plan_local_cache
Представление sr_plan_local_cache предоставляет подробную информацию о зарегистрированных и замороженных операторах в локальном кеше. Столбцы этого представления описываются в Таблице 4.
Таблица 4. Столбцы sr_plan_local_cache
| Столбец Тип | Описание |
|---|---|
| sql_hash bigint | Внутренний идентификатор запроса |
| const_hash bigint | Хеш непараметризованных констант |
| fs_is_frozen boolean | true, если оператор заморожен |
| fs_is_valid boolean | true, если оператор действителен |
| ps_is_valid boolean | true, если оператор должен быть перепроверен |
| query_string text | Запрос, зарегистрированный функцией sr_register_query |
| query text | Внутреннее представление запроса |
| paramtypes regtype[] | Массив с типами параметров, использованных в запросе |
| hintstr text | Набор подсказок, сформированный на основе замороженного плана |
Представление sr_captured_queries
Представление sr_captured_queries предоставляет подробную информацию обо всех запросах, отслеживаемых в сеансах. Столбцы этого представления описываются в Таблице 5.
Таблица 5. Столбцы sr_captured_queries
| Столбец Тип | Описание |
|---|---|
| dbid oid | Идентификатор базы данных, в которой выполняется оператор |
| sql_hash bigint | Внутренний идентификатор запроса |
| queryid bigint | Стандартный идентификатор запроса |
| sample_string text | Запрос, выполненный в режиме автоматического отслеживания запросов |
| query_string text | Параметризованный запрос |
| constants text | Набор констант в запросе |
| prep_consts text | Набор констант, использованных для выполнения (EXECUTE) подготовленного оператора |
| hintstr text | Набор подсказок, сформированный на основе плана |
| explain_plan text | План, отображаемый командой EXPLAIN |
Функции
Вызывать перечисленные ниже функции могут только суперпользователи.
sr_register_query(query_string text) → record
sr_register_query(query_string text, VARIADIC regtype[]) → record
Сохраняет в локальном кеше запрос, описанный в query_string, и возвращает уникальную пару sql_hash и const_hash.
sr_unregister_query() → bool
Удаляет из локального кеша запрос, который был зарегистрирован, но не был заморожен. Если нет ошибок, возвращает true.
sr_plan_freeze(plan_type text) → bool
Замораживает последний использованный план для оператора. Допустимые значения необязательного аргумента plan_type: serialized и hintset. Значение serialized означает, что используется план запроса, основанный на сериализованном представлении. Со значением hintset расширение sr_plan использует план запроса, основанный на наборе подсказок, формирующемся на стадии выполнения зарегистрированного запроса. Если аргумент plan_type опущен, по умолчанию используется план запроса serialized. Если нет ошибок, возвращает true.
sr_plan_unfreeze(sql_hash bigint, const_hash bigint) → bool
Удаляет план только из хранилища и оставляет план, зарегистрированный в локальном кеше. Если нет ошибок, возвращает true.
sr_plan_remove(sql_hash bigint, const_hash bigint) → bool
Удаляет замороженный оператор с указанными sql_hash и const_hash. Действует как вызванные последовательно функции sr_plan_unfreeze и sr_unregister_query. Если нет ошибок, возвращает true.
sr_plan_reset(dbid oid) → bigint
Удаляет все записи в хранилище sr_plan для указанной базы данных. Чтобы удалить данные, собранные sr_plan для текущей базы данных, опустите аргумент dbid. Чтобы сбросить данные для всех баз данных, установите в dbid значение NULL.
sr_reload_frozen_plancache() → bool
Удаляет все замороженные планы и снова загружает их из хранилища. Также эта функция удаляет операторы, которые были зарегистрированы, но не были заморожены.
sr_plan_fs_counter() → table
Возвращает количество использований каждого замороженного оператора и идентификатор базы данных, в которой этот оператор был зарегистрирован и использован.
sr_show_registered_query(sql_hash bigint, const_hash bigint) → table
Возвращает зарегистрированный запрос с указанными sql_hash и const_hash, даже если он не заморожен, только для целей отладки. Это работает, если запрос зарегистрирован в текущем обслуживающем процессе или заморожен в текущей базе данных.
sr_set_plan_type(sql_hash bigint, const_hash bigint, plan_type text) → bool
Устанавливает тип плана запроса для замороженного оператора. Допустимые значения для аргумента plan_type: serialized и hintset. Чтобы иметь возможность использовать план запроса типа hintset, нужно загрузить модуль pg_hint_plan. Если план запроса был успешно изменен, возвращает true.
sr_plan_hintset_update(sql_hash bigint, const_hash bigint, hintset text) → bool
Позволяет изменить сгенерированный набор подсказок на набор пользовательских подсказок. Строка с набором пользовательских подсказок не должна вводиться в специальной форме комментария, как в pg_hint_plan, т. е. она не должна начинаться символами /*+ и заканчиваться символами */. Если план с набором подсказок был успешно изменен, возвращает true.
sr_captured_clean() → bigint
Удаляет все записи из представления sr_captured_queries. Эта функция возвращает количество удаленных записей.
Параметры конфигурации
sr_plan.enable (boolean)
Разрешает sr_plan использовать замороженные планы. Значение по умолчанию —
off. Этот параметр могут изменять только суперпользователи.
sr_plan.fs_ctr_max (integer)
Устанавливает максимальное количество замороженных операторов, возвращаемых
функцией sr_plan_fs_counter(). Значение по умолчанию — 5000. Этот параметр
можно установить только при запуске сервера.
sr_plan.max_items (integer)
Устанавливает максимальное количество записей, с которыми может работать
sr_plan. Значение по умолчанию — 100. Этот параметр можно установить
только при запуске сервера.
sr_plan.auto_tracking (boolean)
Разрешает sr_plan автоматически нормализовать и регистрировать запросы,
выполняемые с помощью команды EXPLAIN. Значение по умолчанию — off. Этот
параметр могут изменять только суперпользователи.
sr_plan.max_local_cache_size (integer)
Устанавливает максимальный размер локального кеша, в килобайтах. Значение по
умолчанию — ноль, что означает отсутствие ограничений. Этот параметр могут
изменять только суперпользователи.
sr_plan.wal_rw (boolean)
Разрешает физическую репликацию данных sr_plan. При значении off на
основном сервере никакие данные с него на резервный сервер не переносятся. При
значении off на резервном сервере все данные, переносящиеся с основного сервера,
игнорируются. Значение по умолчанию — off. Этот параметр можно установить
только при запуске сервера.
sr_plan.auto_capturing (boolean)
Разрешает автоматическое отслеживание запросов в sr_plan. Установка в этом
параметре конфигурации значения on позволяет увидеть в представлении
sr_captured_queries запросы с константами в текстовой форме, а также
параметризованные запросы. Информация о выполненных запросах хранится до
перезапуска сервера. Значение по умолчанию — off. Этот параметр могут изменять
только суперпользователи.
sr_plan.max_captured_items (integer)
Устанавливает максимальное количество запросов, которые может отслеживать sr_plan.
Значение по умолчанию — 1000. Этот параметр можно установить только при запуске
сервера.
sr_plan.max_consts_len (integer)
Устанавливает максимальную длину набора констант в отслеживаемых запросах.
Значение по умолчанию — 100. Этот параметр можно установить только при запуске
сервера.
sr_plan.sandbox (boolean)
Разрешает резервировать отдельную область в разделяемой памяти для использования
основным или резервным узлом, что позволяет тестировать и анализировать запросы
с существующим набором данных без влияния на работу узла. При значении on на
резервном узле sr_plan замораживает планы только на этом узле и хранит их
в «песочнице» — альтернативном хранилище планов. Если же параметр включен на
основном узле, расширение использует отдельную область разделяемой памяти, которая
не реплицируется на резервный узел. При изменении значения этого параметра
сбрасывается кеш sr_plan. Значение по умолчанию — off. Этот параметр
могут изменять только суперпользователи.