68.1. Как это работает #
Если во время выполнения запроса срабатывает триггер AQE, частично выполненный запрос приостанавливается, и AQE пытается его переоптимизировать. Информация об операторе запроса, мощностях узлов непараметризованных узлов и параметризованных узлах с фактическими мощностями, превышающими прогнозы, используется для выбора нового плана и сохраняется для дальнейших переоптимизаций. Затем запрос запускается заново с использованием нового плана. Триггеры AQE могут быть отключены для будущих переоптимизаций того же запроса в следующих ситуациях:
Во время выполнения не были собраны новые данные.
Новый созданный план соответствует уже опробованному.
Достигнуто максимальное количество перезапусков, заданное параметром конфигурации aqe_max_reruns.
В таких случаях выполнение запроса продолжается без прерывания.
Если триггер AQE активирован, запрос, соответствующий условию триггера, выполняется в неявно созданной подтранзакции. В случае перезапуска это помогает выполнять очистку после предыдущего запроса и освобождать системные ресурсы, такие как память или дисковое пространство.
68.1.1. Триггеры AQE #
Следующие триггеры могут прервать запрос и запустить AQE:
Время выполнения запроса: триггер срабатывает, если запрос выполняется дольше, чем указано в параметре конфигурации aqe_sql_execution_time_trigger.
Количество обработанных кортежей узлов: триггер срабатывает, когда количество таких кортежей превышает число, обычно ожидаемое планировщиком, которое умножается на значение параметра конфигурации aqe_rows_underestimation_rate_trigger.
Потребление памяти рабочим процессом: триггер срабатывает, когда потребление памяти рабочим процессом превышает значение параметра конфигурации aqe_backend_memory_used_trigger и срабатывает триггер количества обработанных кортежей узлов.
68.1.2. Подробности адаптивного выполнения запросов #
Если параметр aqe_show_details включён, информация, связанная с AQE, добавляется в вывод команды EXPLAIN ANALYZE
. Раздел SUMMARY
дополнительно включает следующие характеристики:
AQE Active
— срабатывал ли триггер AQE во время выполнения запроса.Table Entries
— количество таблиц в запросе, включая подзапросы.Controlled Statements
— количество операторов, которые были переоптимизированы во время выполнения запроса.AQE Reruns
— общее количество перезапусков запроса.Total Time Elapsed
— общее время выполнения запроса, включая время всех попыток перезапуска. Это свойство отображается только в том случае, если запрос был переоптимизирован и перезапущен хотя бы один раз.Final Run Planning Time
— время планирования последней переоптимизации при адаптивном выполнении запроса. Это свойство отображается только в том случае, если запрос был переоптимизирован и перезапущен хотя бы один раз.
Для каждого узла плана включены следующие характеристики:
NodeSign
— 64-битная подпись (хеш) узла, которая однозначно идентифицирует узел плана запроса. Подписаны не все узлы, а только те, где ошибки модели оценки оптимизатора могут приводить к ошибкам в поиске оптимального плана запроса.Cardinality
— количество кортежей узла плана, достигнутое при предыдущих выполнениях запроса. Доступно только с параметромVERBOSE
.Groups Number
— количество групп, вычисленное для этого узла плана в результате предыдущих выполнений запроса. Доступно только с параметромVERBOSE
.
68.1.3. Пример #
Пример 68.1. Использование AQE
В следующем примере показано использование AQE:
DROP TABLE IF EXISTS aqe_test; CREATE TABLE aqe_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 aqe_test SELECT 1, x, x FROM generate_series(1, 1000000) as x; CREATE INDEX ON aqe_test(x); CREATE INDEX ON aqe_test(y); ANALYZE; -- AQE отключено SET aqe_enable = false; EXPLAIN ANALYZE SELECT FROM aqe_test t1, aqe_test t2, aqe_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; -- AQE включено триггером количества обработанных кортежей SET aqe_enable = true; SET aqe_rows_underestimation_rate_trigger = 2; EXPLAIN ANALYZE SELECT FROM aqe_test t1, aqe_test t2, aqe_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;
Вывод без AQE:
QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------- Nested Loop (cost=14.29..44.44 rows=1 width=0) (actual time=77.493..6778.074 rows=20196 loops=1) -> Nested Loop (cost=13.86..35.98 rows=1 width=4) (actual time=77.472..6722.165 rows=10098 loops=1) -> Index Scan using aqe_test_y_idx on aqe_test t1 (cost=0.43..18.52 rows=1 width=8) (actual time=0.015..0.271 rows=198 loops=1) Index Cond: (y < 100) Filter: (z < 100) -> Bitmap Heap Scan on aqe_test t2 (cost=13.43..17.45 rows=1 width=4) (actual time=33.924..33.940 rows=51 loops=198) Recheck Cond: ((y < 100) AND (t1.x = x)) Filter: (z < 100) Heap Blocks: exact=298 -> BitmapAnd (cost=13.43..13.43 rows=1 width=0) (actual time=33.917..33.917 rows=0 loops=198) -> Bitmap Index Scan on aqe_test_y_idx (cost=0.00..5.97 rows=206 width=0) (actual time=0.016..0.016 rows=198 loops=198) Index Cond: (y < 100) -> Bitmap Index Scan on aqe_test_x_idx (cost=0.00..7.21 rows=371 width=0) (actual time=33.898..33.898 rows=505052 loops=198) Index Cond: (x = t1.x) -> Index Scan using aqe_test_y_idx on aqe_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.804 ms Execution Time: 6779.473 ms (19 rows)
Вывод с AQE:
QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------- Merge Join (cost=1.28..718.25 rows=20196 width=0) (actual time=0.040..31.452 rows=20196 loops=1) NodeSign: 13451128626708613266 Merge Cond: (t1.y = t3.y) -> Nested Loop (cost=0.85..622.63 rows=9998 width=4) (actual time=0.029..8.957 rows=10098 loops=1) NodeSign: 3624220923067346440 Join Filter: (t1.x = t2.x) Rows Removed by Join Filter: 29106 -> Index Scan using aqe_test_y_idx on aqe_test t1 (cost=0.43..18.52 rows=197 width=8) (actual time=0.014..0.181 rows=198 loops=1) NodeSign: 5973269849475827818 Index Cond: (y < 100) Filter: (z < 100) -> Materialize (cost=0.43..19.51 rows=198 width=4) (actual time=0.000..0.013 rows=198 loops=198) NodeSign: subordinate -> Index Scan using aqe_test_y_idx on aqe_test t2 (cost=0.43..18.52 rows=198 width=4) (actual time=0.010..0.182 rows=198 loops=1) NodeSign: 480658296932687531 Index Cond: (y < 100) Filter: (z < 100) -> Index Scan using aqe_test_y_idx on aqe_test t3 (cost=0.43..18.52 rows=19996 width=4) (actual time=0.010..16.026 rows=20096 loops=1) NodeSign: 12407239917974993641 Index Cond: (y < 100) Filter: (z < 100) Planning Time: 214.610 ms Execution Time: 33.130 ms AQE Active: true Table Entries: 3 Controlled Statements: 1 AQE Reruns: 3 Final Run Planning Time: 0.591 ms Total Time Elapsed: 247.740 ms (29 rows)