EXPLAIN

EXPLAIN — показать план выполнения оператора


Синтаксис

EXPLAIN [ ( параметр [, ...] ) ] оператор
EXPLAIN [ ANALYZE ] [ VERBOSE ] оператор
EXPLAIN CACHED_PLAN [ ( параметр [, ...] ) ] queryid
EXPLAIN CACHED_PLAN [ ANALYZE ] [ VERBOSE ] queryid

где параметром может быть:

    ANALYZE [ логическое_значение ]
    VERBOSE [ логическое_значение ]
    COSTS [ логическое_значение ]
    SETTINGS [ логическое_значение ]
    GENERIC_PLAN [ логическое_значение ]
    BUFFERS [ логическое_значение ]
    WAL [ логическое_значение ]
    TIMING [ логическое_значение ]
    SUMMARY [ логическое_значение ]
    FORMAT { TEXT | XML | JSON | YAML }

Описание

Эта команда отображает план выполнения, который планировщик QHB генерирует для предоставленного оператора. План выполнения показывает, как будет сканироваться таблица(ы), на которую ссылается этот оператор: простым последовательным сканированием, сканированием по индексу и т. д. — и если оператор ссылается на несколько таблиц, то какие алгоритмы соединения будут использоваться для объединения требуемых строк из каждой входной таблицы.

Наиболее важной частью выводимой информации является расчетная стоимость выполнения оператора, которая представляет собой предположение планировщика о том, сколько времени потребуется для выполнения этого оператора (это значение измеряется в единицах стоимости, которые не имеют точного определения, но обычно подразумевают обращения к страницам на диске). На самом деле выводятся два числа: начальная стоимость до возвращения первой строки и общая стоимость возвращения всех строк. Для большинства запросов важна общая стоимость, но в таких контекстах, как подзапрос в EXISTS, планировщик выбирает вместо нее наименьшую стартовую стоимость (так как исполнитель все равно остановится сразу после получения одной строки). Кроме того, если ограничить число возвращаемых строк предложением LIMIT, то планировщик создает подходящую интерполяцию между этими предельными значениями стоимости, выбирая наиболее выгодный план.

С параметром ANALYZE оператор будет действительно выполнен, а не только запланирован. При этом в результат добавляется фактическая статистика времени выполнения, включая общее затраченное время в каждом узле плана (в миллисекундах) и общее количество строк, которые тот фактически вернул. Это помогает проверить, близки ли оценки планировщика к реальности.


Важно

Имейте в виду, что с указанием ANALYZE оператор действительно выполняется. Хотя EXPLAIN отбросит результат, который вернула бы SELECT, в остальном все действия произойдут как обычно. Если вы хотите выполнить EXPLAIN ANALYZE с командой INSERT, UPDATE, DELETE, MERGE, CREATE TABLE AS или EXECUTE, не допуская изменения данных этой командой, используйте следующий подход:

BEGIN;
EXPLAIN ANALYZE ...;
ROLLBACK;

Без круглых скобок для этого оператора можно указать только параметры ANALYZE и VERBOSE, и только в таком порядке. Ожидается, что все новые параметры будут поддерживаться только при условии синтаксиса со скобками.


CACHED_PLAN

Если включен разделяемый кеш планов, можно посмотреть план, сохраненный в разделяемом кеше. Для этого необходимо указать параметр CACHED_PLAN, а вместо оператора использовать queryid из представления qhb_sql_plans_info.


Параметры

ANALYZE

Выполнить команду и показать фактическое время выполнения и другую статистику. По умолчанию этот параметр имеет значение FALSE.

VERBOSE

Отобразить дополнительную информацию о плане. В частности, включить список выходных столбцов для каждого узла в дереве плана, имена таблиц и функций, дополненные схемами, всегда помечать переменные в выражениях с псевдонимом их диапазонной таблицы и всегда выводить имена всех триггеров, для которых отображается статистика. Кроме того, будет отображен идентификатор запроса (если он был вычислен); подробную информацию см. в описании параметра compute_query_id. По умолчанию этот параметр имеет значение FALSE.

COSTS

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

SETTINGS

Включить информацию о параметрах конфигурации. В частности, включить параметры, влияющие на планирование запроса, имеющие значение, отличное от встроенного значения по умолчанию. По умолчанию этот параметр имеет значение FALSE.

GENERIC_PLAN

Разрешить оператору содержать местозаполнители (например, $1) и генерировать типовой план, не зависящий от значений этих параметров. Подробную информацию о типовых планах и типах параметров, поддерживающих параметры, см. на справочной странице команды PREPARE. Этот параметр нельзя использовать совместно с ANALYZE. По умолчанию этот параметр имеет значение FALSE.

BUFFERS

Включить информацию об использовании буфера. В частности, включить количество прочитанных, загрязненных и записанных разделяемых блоков, а также количество попаданий в них, количество прочитанных, загрязненных и записанных локальных блоков, а также количество попаданий в них, количество прочитанных и записанных временных блоков, а также время, потраченное на чтение и запись блоков файлов данных и блоков временных файлов (в миллисекундах), если включен параметр track_io_timing. Попадание означает, что чтения удалось избежать, поскольку понадобившийся блок был найден уже находящимся в кеше. Разделяемые блоки содержат данные из обычных таблиц и индексов, локальные — данные из временных таблиц и индексов, а временные — временные рабочие данные, используемые в узлах плана, отвечающих за сортировку, хеширование, материализацию и тому подобное. Количество загрязненных блоков показывает, сколько ранее не модифицированных блоков изменил этот запрос, тогда как количество записанных блоков показывает, сколько ранее загрязненных блоков вытеснил из кеша этот обслуживающий процесс во время обработки запроса. Количество блоков, показанных для узла верхнего уровня, включает блоки, используемые всеми его дочерними узлами. В текстовом формате печатаются только ненулевые значения. По умолчанию этот параметр имеет значение FALSE.

WAL

Включить информацию о генерировании записей WAL. В частности, включить количество записей, количество полных образов страниц (full page images, fpi) и объем сгенерированных записей WAL в байтах. В текстовом формате печатаются только ненулевые значения. Этот параметр можно использовать только при включенном параметре ANALYZE. По умолчанию он имеет значение FALSE.

TIMING

Включить фактическое время запуска и время, затраченное в каждом узле на выходе. Издержки на многократное чтение системных часов могут замедлить запрос в некоторых системах, поэтому когда требуется только подсчет фактического количества строк, а не точное время, может быть полезно установить этот параметр в FALSE. Время выполнения всего оператора всегда измеряется, даже если вывод времени на уровне узлов выключен с помощью этого параметра. Этот параметр можно использовать только при включенном параметре ANALYZE. По умолчанию он имеет значение TRUE.

SUMMARY

Включить сводку (например, информацию о суммарном времени) после плана запроса. При использовании ANALYZE сводная информация выводится по умолчанию, но этот параметр позволяет получить ее и с другими вариантами команды. В EXPLAIN EXECUTE время планирования включает в себя время, требуемое для извлечения плана из кеша, и, при необходимости, время, требуемое для повторного планирования.

FORMAT

Установить формат вывода, который может быть TEXT, XML, JSON или YAML. Нетекстовые форматы содержат ту же информацию, что и текстовые, но больше подходят для программного анализа. По умолчанию этот параметр имеет значение TEXT.

логическое_значение

Определяет, должен ли выбранный параметр быть включен или выключен. Для включения параметра можно написать: TRUE, ON или 1, а для выключения — FALSE, OFF или 0. Кроме того, логическое_значение можно опустить; в этом случае предполагается TRUE.

оператор

Любой оператор SELECT, INSERT, UPDATE, DELETE, MERGE, VALUES, EXECUTE, DECLARE, CREATE TABLE AS или CREATE MATERIALIZED VIEW AS, план выполнения которого вы хотите видеть.


Выводимая информация

Результатом выполнения этой команды является текстовое описание выбранного для оператора плана, при необходимости дополненное статистикой выполнения. Предоставленная информация описывается в разделе Использование EXPLAIN.


Примечания

Чтобы планировщик запросов QHB мог принимать обоснованные решения при оптимизации запросов, данные в pg_statistic должны быть актуальными для всех таблиц, используемых в запросе. Обычно это автоматически обеспечивает процесс «Автовакуум». Но если в содержимом таблицы недавно произошли существенные изменения, может потребоваться вручную выполнить ANALYZE, не дожидаясь, пока до них доберется автоочистка.

Чтобы измерить в плане выполнения стоимость времени выполнения для каждого узла, текущая реализация EXPLAIN ANALYZE добавляет в выполнение запроса издержки на профилирование. В итоге выполнение запроса с EXPLAIN ANALYZE иногда может занять значительно больше времени, чем обычное выполнение запроса. Объем издержек зависит от характера запроса, а также от используемой платформы. Наихудший случай возникает в узлах плана, которые сами по себе требуют очень мало времени на выполнение, и на машинах с относительно медленно выполняющимися вызовами операционной системы на получение текущего времени.


Примеры

Выведение плана простого запроса для таблицы, содержащей единственный столбец integer и 10 000 строк:

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)

Конечно, показанные здесь конкретные цифры зависят от фактического содержания соответствующих таблиц. Также обратите внимание, что числа и даже выбранная стратегия запроса могут отличаться в разных выпусках QHB из-за улучшений планировщика. Кроме того, команда ANALYZE использует случайную выборку для оценки статистики данных, поэтому оценки затрат могут измениться после нового запуска ANALYZE, даже если фактическое распределение данных в таблице не изменилось.

Заметьте, что в предыдущем примере показан «специализированный» план для конкретных значений параметров, заданных в EXECUTE. Также мы можем пожелать ознакомиться с типовым планом для параметризованного запроса, и это можно сделать с помощью GENERIC_PLAN:

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 должны иметь тот же тип данных, что и id, поэтому отсутствие информации о типе параметра из PREPARE не стало проблемой. В других случаях может понадобиться явно указать типы для символов параметров, что можно сделать путем их приведения, например:

EXPLAIN (GENERIC_PLAN)
  SELECT sum(bar) FROM test
    WHERE id > $1::integer AND id < $2::integer
    GROUP BY foo;

Совместимость

В стандарте SQL команда EXPLAIN не определена.


См. также

ANALYZE