EXPLAIN
Эта страница переведена при помощи нейросети GigaChat.
EXPLAIN
- вывод плана выполнения оператора.
Синтаксис
EXPLAIN [ ( option [, ...] ) ] statement
EXPLAIN [ ANALYZE ] [ VERBOSE ] statement
Где option может быть одной из:
ANALYZE [ boolean ]
VERBOSE [ boolean ]
COSTS [ boolean ]
SETTINGS [ boolean ]
GENERIC_PLAN [ boolean ]
BUFFERS [ boolean ]
SERIALIZE [ { NONE | TEXT | BINARY } ]
WAL [ boolean ]
TIMING [ boolean ]
SUMMARY [ boolean ]
MEMORY [ boolean ]
FORMAT { TEXT | XML | JSON | YAML }
Описание
EXPLAIN
отображает план выполнения, который генерирует планировщик PostgreSQL для заданного оператора. План выполнения показывает, как будут сканироваться таблицы, упомянутые в операторе — с помощью последовательного чтения, индексного поиска и так далее. Если задействовано несколько таблиц, также указывается, какой алгоритм соединения будет использоваться для объединения строк из разных таблиц.
Наиболее важной частью вывода являются оценки стоимости выполнения — предположение планировщика о том, сколько ресурсов потребуется для выполнения запроса (в условных единицах, обычно отражающих количество обращений к страницам на диске). Отображаются два значения:
- стоимость запуска — до получения первой строки;
- общая стоимость — до получения всех строк.
Обычно важна общая стоимость, но в некоторых случаях (например, подзапрос с EXISTS
) выбирается план с минимальной стартовой стоимостью, так как выполнение прекращается после первой строки. При использовании LIMIT
планировщик делает интерполяцию между стартовой и полной стоимостью, чтобы выбрать наименее затратный план.
Параметр ANALYZE
приводит к фактическому выполнению запроса, а не только построению плана. Тогда к плану добавляется статистика реального выполнения — время выполнения каждого узла (в миллисекундах), количество возвращенных строк и другое. Это полезно для оценки точности предположений планировщика.
Важно
Имейте в виду, что оператор фактически выполняется при использовании ANALYZE
. Хотя EXPLAIN
отбросит любой вывод, который мог бы вернуть SELECT
, другие побочные эффекты оператора будут происходить как обычно. Если нужно использовать EXPLAIN ANALYZE
для INSERT
, UPDATE
, DELETE
, MERGE
, CREATE TABLE AS
или EXECUTE
оператора без воздействия команды на данные, используйте этот подход:
BEGIN;
EXPLAIN ANALYZE ...;
ROLLBACK;
Параметры
ANALYZE
- Выполняет команду и добавляет статистику выполнения. По умолчанию
FALSE
.
VERBOSE
- Выводит дополнительную информацию: список выходных столбцов для каждого узла плана, имена таблиц и функций с указанием схем, имена переменных, имена триггеров и идентификатор запроса (если включен compute_query_id). По умолчанию
FALSE
.
COSTS
- Показывает оценочную стартовую и общую стоимость, количество строк и ширину строк для каждого узла плана. По умолчанию
TRUE
.
SETTINGS
- Показывает параметры конфигурации, отличающиеся от значений по умолчанию и влияющие на планирование. По умолчанию
FALSE
.
GENERIC_PLAN
- Позволяет оператору содержать заполнители параметров, подобные
$1
, и генерировать общий план, который не зависит от значений этих параметров. См. раздел PREPARE для получения подробностей об общих планах и типах операторов, поддерживающих параметры. Этот параметр нельзя использовать совместно сANALYZE
. Он принимает значение по умолчаниюFALSE
.
BUFFERS
- Включите информацию об использовании буферов. В частности, включите количество совпадающих блоков общего доступа, считанных, испорченных и записанных блоков, количество локальных совпадающих блоков, считанных, испорченных и записанных блоков, количество временных блоков, считываемых и записываемых, а также время, потраченное на чтение и запись блоков данных файлов, локальных блоков и временных файловых блоков (в миллисекундах), если включена опция
track_io_timing
. Совпадениеhit
означает, что операция чтения была предотвращена, поскольку блок уже находился в кеше при необходимости. Общие блоки содержат данные из обычных таблиц и индексов. Локальные блоки содержат данные из временных таблиц и индексов. Временные блоки содержат краткосрочные рабочие данные, используемые при сортировке, хешировании, узлах планаMaterialize
и аналогичных случаях. Число блоковdirtied
указывает количество ранее неизмененных блоков, измененных этим запросом, число блоковwritten
указывает количество ранее загрязненных блоков, вытесненных из кеша данным сервером во время обработки запроса. Количество блоков, указанное для верхнего уровня узла, включает те, которые используются всеми его дочерними узлами. В текстовом формате отображаются только ненулевые значения. По умолчанию этот параметр равенFALSE
.
SERIALIZE
- Включить информацию о стоимости сериализации выходных данных запроса, то есть преобразования их в текстовый или двоичный формат для отправки клиенту. Это может составлять значительную часть времени, необходимого для обычного выполнения запроса, если функции вывода типов данных дороги или необходимо извлечь значения TOAST из внестрочного хранилища. Поведение
EXPLAIN
по умолчанию,SERIALIZE NONE
, не выполняет таких преобразований. Если указаноSERIALIZE TEXT
илиSERIALIZE BINARY
, выполняются соответствующие преобразования, и измеряется время, затрачиваемое на них (если не указана опцияTIMING OFF
). Если также указан параметрBUFFERS
, то учитываются любые обращения к буферам, связанные с этими преобразованиями. Однако ни в коем случаеEXPLAIN
не отправляет полученные данные клиенту, следовательно, таким образом невозможно исследовать затраты на передачу по сети. Сериализация возможна только тогда, когда также включен параметрANALYZE
. ЕслиSERIALIZE
написано без аргумента, предполагаетсяTEXT
.
WAL
- Показывает информацию о создании WAL-записей: количество записей, образов страниц (FPI) и общий объем в байтах. Работает только при
ANALYZE = TRUE
. По умолчаниюFALSE
.
TIMING
- Показывает фактическое время старта и выполнения каждого узла. На некоторых платформах это может значительно замедлить выполнение, поэтому можно отключить. Общее время выполнения всегда отображается. Работает только при
ANALYZE = TRUE
. По умолчаниюTRUE
.
SUMMARY
- Показывает сводную информацию после плана (включается по умолчанию с
ANALYZE
, но отключена без него). Включает, например, суммарное время выполнения. Планирование вEXPLAIN EXECUTE
учитывает время извлечения плана из кеша и время перепланирования, если оно произошло.
MEMORY
- Включить информацию о потреблении памяти фазой планирования запросов. В частности, укажите точное количество используемой оперативной памяти структурами данных генератора планов, а также общую память с учетом накладных расходов на выделение. Этот параметр по умолчанию равен
FALSE
.
FORMAT
- Указывает формат вывода:
TEXT
, XML, JSON, YAML. Все форматы содержат одинаковую информацию, но машинные форматы проще парсить. По умолчаниюTEXT
.
boolean
- Указывает, включен параметр или нет:
TRUE
,ON
, 1 — включено;FALSE
,OFF
, 0 — выключено. Можно опустить значение — считается, что параметр включен.
statement
- Любое
SELECT
,INSERT
,UPDATE
,DELETE
,MERGE
,VALUES
,EXECUTE
,DECLARE
,CREATE TABLE AS
, илиCREATE MATERIALIZED VIEW AS
утверждение, план выполнения которого необходимо увидеть.
Выводимая информация
Результат команды представляет собой текстовое описание выбранного плана выполнения, при необходимости дополненное статистикой выполнения.
Примечания
Чтобы планировщик PostgreSQL мог точно оценивать планы, данные в представлении pg_statistic должны быть актуальны. Обычно этим занимается автоочистка (autovacuum). Однако при существенных изменениях в таблице может потребоваться вручную вызвать ANALYZE.
Команда EXPLAIN ANALYZE
добавляет накладные расходы на профилирование, что может сделать выполнение запроса значительно медленнее по сравнению с обычным запуском. Степень замедления зависит от сложности запроса и операционной системы. В наихудшем случае (например, если план содержит быстрые узлы) накладные расходы могут быть существенными, особенно если системные вызовы для получения текущего времени работают медленно.
Примеры
Чтобы показать план простого запроса для таблицы с одним столбцом integer
и 10000 строк:
EXPLAIN SELECT * FROM foo;
QUERY PLAN
---------------------------------------------------------
Seq Scan on foo (cost=0.00..155.00 rows=10000 width=4)
(1 row)
Вот тот же запрос с форматом вывода JSON:
EXPLAIN (FORMAT JSON) SELECT * FROM foo;
QUERY PLAN
--------------------------------
[ +
{ +
"Plan": { +
"Node Type": "Seq Scan",+
"Relation Name": "foo", +
"Alias": "foo", +
"Startup Cost": 0.00, +
"Total Cost": 155.00, +
"Plan Rows": 10000, +
"Plan Width": 4 +
} +
} +
]
(1 row)
Если есть индекс и используется запрос с условием индексации WHERE
, EXPLAIN
может показать другой план:
EXPLAIN SELECT * FROM foo WHERE i = 4;
QUERY PLAN
--------------------------------------------------------------
Index Scan using fi on foo (cost=0.00..5.98 rows=1 width=4)
Index Cond: (i = 4)
(2 rows)
Вот тот же запрос, но в формате YAML:
EXPLAIN (FORMAT YAML) SELECT * FROM foo WHERE i='4';
QUERY PLAN
-------------------------------
- Plan: +
Node Type: "Index Scan" +
Scan Direction: "Forward"+
Index Name: "fi" +
Relation Name: "foo" +
Alias: "foo" +
Startup Cost: 0.00 +
Total Cost: 5.98 +
Plan Rows: 1 +
Plan Width: 4 +
Index Cond: "(i = 4)"
(1 row)
Формат XML оставлен для читателя в качестве упражнения.
Вот тот же план с подавленными оценками затрат:
EXPLAIN (COSTS FALSE) SELECT * FROM foo WHERE i = 4;
QUERY PLAN
----------------------------
Index Scan using fi on foo
Index Cond: (i = 4)
(2 rows)
Вот пример плана запроса для запроса, использующего агрегатную функцию:
EXPLAIN SELECT sum(i) FROM foo WHERE i < 10;
QUERY PLAN
---------------------------------------------------------------------
Aggregate (cost=23.93..23.93 rows=1 width=4)
-> Index Scan using fi on foo (cost=0.00..23.92 rows=6 width=4)
Index Cond: (i < 10)
(3 rows)
Вот пример использования EXPLAIN EXECUTE
для отображения плана выполнения подготовленного запроса:
PREPARE query(int, int) AS SELECT sum(bar) FROM test
WHERE id > $1 AND id < $2
GROUP BY foo;
EXPLAIN ANALYZE EXECUTE query(100, 200);
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=10.77..10.87 rows=10 width=12) (actual time=0.043..0.044 rows=10 loops=1)
Group Key: foo
Batches: 1 Memory Usage: 24kB
-> Index Scan using test_pkey on test (cost=0.29..10.27 rows=99 width=8) (actual time=0.009..0.025 rows=99 loops=1)
Index Cond: ((id > 100) AND (id < 200))
Planning Time: 0.244 ms
Execution Time: 0.073 ms
(7 rows)
Конечно, конкретные числа, показанные здесь, зависят от фактического содержимого задействованных таблиц. Также обратите внимание, что цифры и даже выбранная стратегия запроса могут варьироваться между версиями PostgreSQL из-за улучшений планировщика. Кроме того, команда ANALYZE
использует случайную выборку для оценки статистики данных, поэтому возможно изменение оценок затрат после свежего запуска ANALYZE
, даже если фактическое распределение данных в таблице не изменилось.
Обратите внимание, что предыдущий пример показал «индивидуальный» план для конкретных значений параметров, указанных в команде EXECUTE
. Можно захотеть увидеть общий план для параметризованного запроса, который можно сделать с помощью команды EXPLAIN (FORMAT TEXT)
:
EXPLAIN (GENERIC_PLAN)
SELECT sum(bar) FROM test
WHERE id > $1 AND id < $2
GROUP BY foo;
QUERY PLAN
-------------------------------------------------------------------------------
HashAggregate (cost=26.79..26.89 rows=10 width=12)
Group Key: foo
-> Index Scan using test_pkey on test (cost=0.29..24.29 rows=500 width=8)
Index Cond: ((id > $1) AND (id < $2))
(4 rows)
В данном случае парсер правильно определил, что параметры $1
и $2
должны иметь такой же тип данных, как и столбец my_column
, так что отсутствие информации о типах параметров из команды PREPARE
не было проблемой. В других случаях может понадобиться явно указать типы данных для символов параметров, что можно сделать путем их приведения, например:
EXPLAIN (GENERIC_PLAN)
SELECT sum(bar) FROM test
WHERE id > $1::integer AND id < $2::integer
GROUP BY foo;
Совместимость
В стандарте SQL нет определения оператора EXPLAIN
.
Следующий синтаксис использовался до версии PostgreSQL 9.0 и все еще поддерживается:
EXPLAIN [ ANALYZE ] [ VERBOSE ] statement
Обратите внимание, что в этом синтаксисе опции должны указываться именно в том порядке, как показано выше.