77.1. Как это работает #
Если во время выполнения запроса срабатывает триггер перепланирования, частично выполненный запрос приостанавливается, и перепланирование в реальном времени пытается его переоптимизировать. Информация об операторе запроса, мощностях узлов непараметризованных узлов и параметризованных узлах с фактическими мощностями, превышающими прогнозы, используется для выбора нового плана и сохраняется для дальнейших переоптимизаций. Затем запрос запускается заново с использованием нового плана. Триггеры перепланирования могут быть отключены для будущих переоптимизаций того же запроса в следующих ситуациях:
Во время выполнения не были собраны новые данные.
Новый созданный план соответствует уже опробованному.
Достигнуто максимальное количество перезапусков, заданное параметром конфигурации replan_max_attempts.
В таких случаях выполнение запроса продолжается без прерывания.
Если триггер перепланирования активирован, запрос, соответствующий условию триггера, выполняется в неявно созданной подтранзакции. В случае перепланирования это помогает выполнять очистку после предыдущего запроса и освобождать системные ресурсы, такие как память или дисковое пространство.
77.1.1. Триггеры перепланирования #
Следующие триггеры могут прервать запрос и запустить перепланирование:
Время выполнения запроса: триггер срабатывает, если запрос выполняется дольше, чем указано в параметре конфигурации replan_query_execution_time.
Количество обработанных кортежей узлов: триггер срабатывает, когда количество таких кортежей превышает число, обычно ожидаемое планировщиком, которое умножается на значение параметра конфигурации replan_overrun_limit.
Потребление памяти рабочим процессом: триггер срабатывает, когда потребление памяти рабочим процессом превышает значение параметра конфигурации replan_memory_limit и срабатывает триггер количества обработанных кортежей узлов.
77.1.2. Просмотр подробностей о перепланировании #
Если параметр replan_show_signature включён, информация, связанная с перепланированием, добавляется в вывод команды EXPLAIN ANALYZE
. Раздел SUMMARY
дополнительно включает следующие характеристики:
Replan Active
— срабатывал ли триггер перепланирования во время выполнения запроса.Table Entries
— количество таблиц в запросе, включая подзапросы.Controlled Statements
— количество операторов, которые были перепланированы во время выполнения запроса.Replanning Attempts
— общее количество перезапусков/попыток перепланирования запроса.Total Time Elapsed
— общее время выполнения запроса, включая время всех попыток перезапуска/перепланирования. Это свойство отображается только в том случае, если запрос был переоптимизирован и перезапущен хотя бы один раз.Final Run Planning Time
— время планирования последней переоптимизации при перепланировании. Это свойство отображается только в том случае, если запрос был переоптимизирован и перезапущен хотя бы один раз.
Для каждого узла плана включены следующие характеристики:
NodeSign
— 64-битная подпись (хеш) узла, которая однозначно идентифицирует узел плана запроса. Подписаны не все узлы, а только те, где ошибки модели оценки оптимизатора могут приводить к ошибкам в поиске оптимального плана запроса.Cardinality
— количество кортежей узла плана, достигнутое при предыдущих выполнениях запроса. Доступно только с параметромVERBOSE
.Groups Number
— количество групп, вычисленное для этого узла плана в результате предыдущих выполнений запроса. Доступно только с параметромVERBOSE
.
77.1.3. Пример #
Пример 77.1. Использование перепланирования
В следующем примере показано использование перепланирования:
DROP TABLE IF EXISTS replan_test; CREATE TABLE replan_test WITH (autovacuum_enabled=off) AS SELECT x as x, x as y, x as z from generate_series(1, 100000) as x; INSERT INTO replan_test SELECT 1, x, x FROM generate_series(1, 1000000) as x; CREATE INDEX ON replan_test(x); CREATE INDEX ON replan_test(y); ANALYZE; set replan_show_signature = true; -- Перепланирование отключено SET replan_enable = false; EXPLAIN ANALYZE SELECT FROM replan_test t1, replan_test t2, replan_test t3 WHERE t1.x = t2.x and t1.y = t3.y and t1.y < 100 and t1.z < 100 and t2.y < 100 and t2.z < 100 and t3.y < 100 and t3.z < 100; -- Перепланирование включено триггером количества обработанных кортежей SET replan_enable = true; SET replan_overrun_limit = 2; EXPLAIN ANALYZE SELECT FROM replan_test t1, replan_test t2, replan_test t3 WHERE t1.x = t2.x and t1.y = t3.y and t1.y < 100 and t1.z < 100 and t2.y < 100 and t2.z < 100 and t3.y < 100 and t3.z < 100;
Вывод без перепланирования:
QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------- Nested Loop (cost=14.30..45.18 rows=1 width=0) (actual time=73.677..6848.136 rows=20196 loops=1) -> Nested Loop (cost=13.87..36.72 rows=1 width=4) (actual time=73.654..6792.731 rows=10098 loops=1) -> Index Scan using replan_test_y_idx on replan_test t1 (cost=0.43..19.25 rows=1 width=8) (actual time=0.014..0.271 rows=198 loops=1) Index Cond: (y < 100) Filter: (z < 100) -> Bitmap Heap Scan on replan_test t2 (cost=13.44..17.46 rows=1 width=4) (actual time=34.278..34.295 rows=51 loops=198) Recheck Cond: ((y < 100) AND (t1.x = x)) Filter: (z < 100) Heap Blocks: exact=298 -> BitmapAnd (cost=13.44..13.44 rows=1 width=0) (actual time=34.268..34.268 rows=0 loops=198) -> Bitmap Index Scan on replan_test_y_idx (cost=0.00..6.08 rows=221 width=0) (actual time=0.016..0.016 rows=198 loops=198) Index Cond: (y < 100) -> Bitmap Index Scan on replan_test_x_idx (cost=0.00..7.11 rows=357 width=0) (actual time=34.248..34.248 rows=505052 loops=198) Index Cond: (x = t1.x) -> Index Scan using replan_test_y_idx on replan_test t3 (cost=0.43..8.45 rows=1 width=4) (actual time=0.004..0.005 rows=2 loops=10098) Index Cond: ((y = t1.y) AND (y < 100)) Filter: (z < 100) Planning Time: 0.722 ms Execution Time: 6849.539 ms (19 rows)
Вывод с перепланированием:
QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------- Merge Join (cost=1.28..720.49 rows=20196 width=0) (actual time=0.038..30.495 rows=20196 loops=1) NodeSign: 16399548477598347697 Merge Cond: (t1.y = t3.y) -> Nested Loop (cost=0.85..624.08 rows=9998 width=4) (actual time=0.027..8.577 rows=10098 loops=1) NodeSign: 6806589677965256871 Join Filter: (t1.x = t2.x) Rows Removed by Join Filter: 29106 -> Index Scan using replan_test_y_idx on replan_test t1 (cost=0.43..19.25 rows=197 width=8) (actual time=0.014..0.180 rows=198 loops=1) NodeSign: 17234727896600901988 Index Cond: (y < 100) Filter: (z < 100) -> Materialize (cost=0.43..20.24 rows=198 width=4) (actual time=0.000..0.013 rows=198 loops=198) NodeSign: subordinate -> Index Scan using replan_test_y_idx on replan_test t2 (cost=0.43..19.25 rows=198 width=4) (actual time=0.010..0.180 rows=198 loops=1) NodeSign: 8157818216567004834 Index Cond: (y < 100) Filter: (z < 100) -> Index Scan using replan_test_y_idx on replan_test t3 (cost=0.43..19.25 rows=19996 width=4) (actual time=0.009..15.417 rows=20096 loops=1) NodeSign: 12097487659300777104 Index Cond: (y < 100) Filter: (z < 100) Planning Time: 252.050 ms Execution Time: 32.169 ms Replan Active: true Table Entries: 3 Controlled Statements: 1 Replanning Attempts: 3 Final Run Planning Time: 0.612 ms Total Time Elapsed: 284.219 ms (29 rows)