77.1. Как это работает #

Если во время выполнения запроса срабатывает триггер перепланирования, частично выполненный запрос приостанавливается, и перепланирование в реальном времени пытается его переоптимизировать. Информация об операторе запроса, мощностях узлов непараметризованных узлов и параметризованных узлах с фактическими мощностями, превышающими прогнозы, используется для выбора нового плана и сохраняется для дальнейших переоптимизаций. Затем запрос запускается заново с использованием нового плана. Триггеры перепланирования могут быть отключены для будущих переоптимизаций того же запроса в следующих ситуациях:

  • Во время выполнения не было получено новых данных. В этом случае вывод команды EXPLAIN ANALYZE содержит сообщение: Replan Deactivation Reason: no new learning data (причина отключения перепланирования: отсутствуют новые данные для обучения).

  • Сформированный повторно план совпадает с ранее использованным. В этом случае вывод команды EXPLAIN ANALYZE содержит сообщение: Replan Deactivation Reason: repeated plan (причина отключения перепланирования: повторный план).

  • Достигнуто максимальное количество перезапусков, заданное параметром конфигурации replan_max_attempts. В этом случае вывод команды EXPLAIN ANALYZE содержит сообщение: Replan Deactivation Reason: attempt limit reached (причина отключения перепланирования: достигнут лимит попыток).

  • Расширение, например pgpro_multiplan, отключило триггеры перепланирования. В этом случае вывод команды EXPLAIN ANALYZE содержит сообщение: Replan Deactivation Reason: external deactivation (причина отключения перепланирования: внешнее отключение).

В таких случаях выполнение запроса продолжается без прерывания.

Если триггер перепланирования активирован, запрос, соответствующий условию триггера, выполняется в неявно созданной подтранзакции. В случае перепланирования это помогает выполнять очистку после предыдущего запроса и освобождать системные ресурсы, такие как память или дисковое пространство.

77.1.1. Триггеры перепланирования #

Следующие триггеры могут прервать запрос и запустить перепланирование:

  • Время выполнения запроса: триггер срабатывает, если запрос выполняется дольше, чем указано в параметре конфигурации replan_query_execution_time.

  • Количество обработанных кортежей узлов: триггер срабатывает, когда количество таких кортежей превышает число, обычно ожидаемое планировщиком, которое умножается на значение параметра конфигурации replan_overrun_limit.

  • Потребление памяти рабочим процессом: триггер срабатывает, когда потребление памяти рабочим процессом превышает значение параметра конфигурации replan_memory_limit и срабатывает триггер количества обработанных кортежей узлов.

  • Ручной триггер: срабатывает, когда пользователь вызывает функцию replan_signal из другого сеанса. В отличие от остальных триггеров, этот триггер не может быть отключён.

77.1.2. Просмотр подробностей о перепланировании #

Если параметр replan_show_signature включён, информация, связанная с перепланированием, добавляется в вывод команды EXPLAIN ANALYZE. Раздел SUMMARY дополнительно включает следующие характеристики:

  • Replan Active — был ли механизм перепланирования активен к моменту завершения выполнения запроса.

  • Table Entries — количество таблиц в запросе, включая подзапросы.

  • Controlled Statements — количество операторов, которые были перепланированы во время выполнения запроса.

  • Replanning Attempts — общее количество перезапусков/попыток перепланирования запроса.

  • Total Time Elapsed — общее время выполнения запроса, включая время всех попыток перезапуска/перепланирования. Это свойство отображается только в том случае, если запрос был переоптимизирован и перезапущен хотя бы один раз.

  • Final Run Planning Time — время планирования последней переоптимизации при перепланировании. Это свойство отображается только в том случае, если запрос был переоптимизирован и перезапущен хотя бы один раз.

  • Replan Deactivation Reason — причина отключения перепланирования. Возможные значения: attempt limit reached (достигнут лимит попыток), repeated plan (повторный план), no new learning data (отсутствуют новые данные для обучения) или external deactivation (внешнее отключение). Отображается только в том случае, если перепланирование не было активно к моменту завершения выполнения запроса.

Для каждого узла плана включены следующие характеристики:

  • NodeSign — 64-битная подпись (хеш) узла, которая однозначно идентифицирует узел плана запроса. Подписаны не все узлы, а только те, где ошибки модели оценки оптимизатора могут приводить к ошибкам в поиске оптимального плана запроса.

  • Cardinality — количество кортежей узла плана, достигнутое при предыдущих выполнениях запроса. Доступно только с параметром VERBOSE.

  • Groups Number — количество групп, вычисленное для этого узла плана в результате предыдущих выполнений запроса. Доступно только с параметром VERBOSE.

77.1.3. Интеграция с pgpro_multiplan #

Перепланирование запросов в реальном времени может работать совместно с расширением pgpro_multiplan, предоставляя следующие возможности:

77.1.4. Пример #

Пример 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)

77.1. How It Works #

If a replan trigger fires during query execution, the partially executed query is paused, and real-time query replanning attempts to reoptimize it. Information about the query statement, node cardinalities of non-parameterized nodes and parameterized nodes with actual cardinalities larger than predicted is used to choose a new plan and is stored for further reoptimizations. Then the query is rerun using the new plan. Replan triggers may be disabled for future reoptimizations of the same query in the following situations:

  • No new information was gathered during execution. In this case, the output of EXPLAIN ANALYZE includes the text: Replan Deactivation Reason: no new learning data.

  • The newly generated plan matches a plan that was already tried. In this case, the output of EXPLAIN ANALYZE includes the text: Replan Deactivation Reason: repeated plan.

  • The maximum number of reruns, set by the replan_max_attempts configuration parameter, was reached. In this case, the output of EXPLAIN ANALYZE includes the text: Replan Deactivation Reason: attempt limit reached.

  • An extension, such as pgpro_multiplan, disabled triggers. In this case, the output of EXPLAIN ANALYZE includes the text: Replan Deactivation Reason: external deactivation.

In such cases, the query execution continues without interruption.

If a replan trigger is activated, a query that meets the trigger condition is executed in an implicitly created subtransaction. In the event of replanning, this helps in cleaning up after a previous execution and releasing system resources, such as memory or disc space.

77.1.1. Replan Triggers #

The following triggers can interrupt a query and launch replanning:

  • Query execution time: the trigger fires when the query runs longer than the value of the replan_query_execution_time configuration parameter.

  • Number of processed node tuples: the trigger fires when this number exceeds the number normally expected by the planner, which is multiplied by the value of the replan_overrun_limit configuration parameter.

  • Backend memory consumption: the trigger fires when memory consumption of a backend exceeds the value of the replan_memory_limit configuration parameter and the number of processed node tuples trigger fired.

  • Manual trigger: the trigger fires when the user calls replan_signal from another session. Unlike other triggers, this trigger cannot be deactivated.

77.1.2. Viewing Replanning Details #

If replan_show_signature is on, information related to replanning is included in the EXPLAIN ANALYZE output. The SUMMARY section additionally includes the following characteristics:

  • Replan Active — whether replanning was active by the end of the query execution.

  • Table Entries — number of tables in the query, including subqueries.

  • Controlled Statements — number of statements that were replanned during execution of the query.

  • Replanning Attempts — total number of the query reruns/replanning attempts.

  • Total Time Elapsed — total time of the query execution including the time of all reruns/replanning attempts. This property is only displayed if the query was reoptimized and rerun at least once.

  • Final Run Planning Time — planning time during last replanning reoptimization. This property is only displayed if the query was reoptimized and rerun at least once.

  • Replan Deactivation Reason — what caused replanning to be disabled. Possible values are self-explanatory: attempt limit reached, repeated plan, no new learning data, or external deactivation. Displayed only if replanning was not active by the end of the query execution.

For each plan node, the following characteristics are included:

  • NodeSign — a 64-bit signature (hash) of the node that uniquely identifies the node of the query plan. Not all nodes are signed, but only those where errors of the optimizer estimation model can cause errors in searching the optimal query plan.

  • Cardinality — cardinality of the plan node achieved in previous executions of the query. Only available with the VERBOSE parameter.

  • Groups Number — number of groups computed for this plan node from previous executions of the query. Only available with the VERBOSE parameter.

77.1.3. Integration with pgpro_multiplan #

Real-time query replanning can work in conjunction with the pgpro_multiplan extension providing the following features:

77.1.4. Example #

Example 77.1. Using Replanning

The following example illustrates replanning:

  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;

  -- Replanning is disabled
  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;

  -- Replanning is enabled with node tuples underestimation trigger
  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;
  

Output without replanning:

                                                                      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)

Output with replanning:

                                                                      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)

FAQ