EXPLAIN
Отображает план выполнения запроса для оператора.
Синтаксис
EXPLAIN [ ( <option> [, ...] ) ] <statement>
EXPLAIN [ANALYZE] [VERBOSE] <statement>
где option может быть одним из следующих:
ANALYZE [ <boolean> ]
VERBOSE [ <boolean> ]
COSTS [ <boolean> ]
BUFFERS [ <boolean> ]
TIMING [ <boolean> ]
FORMAT { TEXT | XML | JSON | YAML }
Описание
EXPLAIN отображает план выполнения запроса, который оптимизатор GPORCA или планировщик Postgres создают для указанного оператора.
План выполнения представляет собой дерево узлов.
Каждый узел плана соответствует отдельной операции: сканированию таблицы, соединению, агрегации или сортировке.
План следует читать снизу вверх: каждый узел передает строки узлу, расположенному непосредственно над ним. Узлы нижнего уровня обычно выполняют операции сканирования таблиц: последовательное, индексное или по bitmap-индексу. Если запрос включает соединения, агрегации, сортировки или другие операции над строками, над узлами сканирования добавляются дополнительные узлы, выполняющие эти действия. Узлы верхнего уровня обычно представляют собой узлы перемещения данных (motion) Greengage DB: повторное распределение (redistribute), явное повторное распределение (explicit redistribute), широковещательная передача (broadcast) или сборка (gather). Эти операции перемещают строки между сегментами во время выполнения запроса.
Вывод EXPLAIN содержит по одной строке для каждого узла дерева плана и показывает тип узла, а также следующие оценки стоимости выполнения, рассчитанные планировщиком:
-
cost— оценка времени выполнения оператора (измеряется в условных единицах стоимости, которые обычно соответствуют обращениям к страницам диска). Указываются два значения стоимости: стартовая стоимость получения первой строки и общая стоимость получения всех строк. Обратите внимание: общая стоимость предполагает получение всех строк, что не всегда соответствует действительности (например, при использованииLIMIT). -
rows— количество строк, возвращаемых данным узлом плана. Обычно это значение меньше числа сканируемых или обрабатываемых узлом строк, поскольку учитывает селективность условийWHERE. Для верхнего узла оценка должна примерно соответствовать количеству строк, которые фактически возвращает, обновляет или удаляет запрос. -
width— оценочный средний размер (в байтах) одной строки, выводимой этим узлом плана.
Важно отметить, что стоимость узла включает стоимость его дочерних узлов. Верхний узел плана содержит оценку общей стоимости выполнения плана. Планировщик старается минимизировать это значение. Также важно понимать, что стоимость отражает только те аспекты выполнения плана, которые учитывает оптимизатор запросов. В частности, стоимость не учитывает время, затрачиваемое на передачу строк клиенту.
EXPLAIN ANALYZE фактически выполняет оператор, а не только строит его план.
План EXPLAIN ANALYZE показывает фактические результаты выполнения вместе с оценками планировщика.
Это позволяет проверить точность оценок планировщика.
Кроме информации, предоставляемой обычным EXPLAIN, EXPLAIN ANALYZE выводит следующие дополнительные сведения:
-
Общее время выполнения запроса (в миллисекундах).
-
Количество обработчиков (сегментов), участвующих в выполнении узла плана. Учитываются только те сегменты, которые вернули строки.
-
Максимальное число строк, возвращенных одним сегментом в операции. Если несколько сегментов вернули одинаковое число строк, выбирается тот, который завершился последним.
-
ID сегмента, вернувшего наибольшее число строк в операции.
-
Для соответствующих операций — объем используемой рабочей памяти (
work_mem). Еслиwork_memнедостаточно, план показывает объем данных, сброшенных на диск, и количество проходов, потребовавшихся наименее производительному сегменту. Например:Work_mem used: 64K bytes avg, 64K bytes max (seg0). Work_mem wanted: 90K bytes avg, 90K bytes max (seg0) to abate workfile I/O affecting 2 workers. [seg0] pass 0: 488 groups made from 488 rows; 263 rows written to workfile [seg0] pass 1: 263 groups made from 263 rows
-
Время (в миллисекундах), затраченное сегментом, который вернул наибольшее число строк, на получение первой строки и всех строк. Значение
timeдо возврата первой строки может не отображаться, если оно совпадает со временем получения всех строк.
Обратите внимание: при использовании ANALYZE оператор фактически выполняется.
Хотя EXPLAIN ANALYZE отбрасывает результат запроса, оператор выполняется полностью, а его побочные эффекты сохраняются.
Если требуется применить EXPLAIN ANALYZE к DML-оператору без изменения данных, используйте следующий подход:
BEGIN;
EXPLAIN ANALYZE ...;
ROLLBACK;
Параметры ANALYZE и VERBOSE могут быть указаны только в этом порядке, без заключения списка параметров в круглые скобки.
Параметры
| Параметр | Описание |
|---|---|
ANALYZE |
Выполняет команду и отображает фактическое время выполнения и другую статистику.
По умолчанию |
VERBOSE |
Отображает дополнительную информацию о плане.
В частности, выводит список выходных столбцов для каждого узла дерева плана, имена таблиц и функций с указанием схемы, помечает переменные в выражениях их псевдонимами из таблицы диапазонов и показывает имя каждого триггера, для которого собирается статистика.
По умолчанию |
COSTS |
Включает информацию об оценочной стартовой и общей стоимости каждого узла плана, а также оценочное количество строк и их размер.
По умолчанию |
BUFFERS |
Включает информацию об использовании буферов.
Может быть указан только вместе с ПРИМЕЧАНИЕ
Greengage DB не поддерживает указание |
TIMING |
Включает в вывод фактическое время запуска и время, затраченное на каждый узел.
Накладные расходы на многократное чтение системных часов могут значительно замедлить выполнение запроса, поэтому может быть полезно установить этот параметр в |
FORMAT |
Задает формат вывода: |
boolean |
Указывает, включить или отключить выбранный параметр.
Для включения можно использовать |
statement |
Любой оператор |
Примечания
Для того чтобы оптимизатор запросов принимал обоснованные решения, необходимо выполнить оператор ANALYZE для сбора статистики о распределении данных в таблице.
Если это не было сделано или если статистика значительно изменилась с момента последнего выполнения ANALYZE, оценочная стоимость, рассчитанная планировщиком, может не соответствовать фактическим характеристикам запроса, что приведет к выбору неоптимального плана.
SQL-оператор, выполняемый во время EXPLAIN ANALYZE, не участвует в ресурсных очередях Greengage DB.
Примеры
Чтобы проиллюстрировать, как читать план запроса EXPLAIN, можно рассмотреть следующий запрос:
EXPLAIN
SELECT *
FROM names
WHERE name = 'Joelle';
Результат:
QUERY PLAN
-------------------------------------------------------------------------------
Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..431.27 rows=1 width=58)
-> Seq Scan on names (cost=0.00..431.27 rows=1 width=58)
Filter: (name = 'Joelle'::text)
Optimizer: Pivotal Optimizer (GPORCA)
(4 rows)
Читая план снизу вверх, видно, что оптимизатор запросов начинает с последовательного сканирования таблицы names.
Обратите внимание, что выражение WHERE применяется как фильтр (Filter).
Это означает, что операция сканирования проверяет условие для каждой строки и возвращает только те строки, которые ему соответствуют.
Результаты сканирования передаются узлу Gather Motion.
В Greengage DB Gather Motion — это операция, при которой сегменты отправляют строки на мастер.
В данном примере три сегмента отправляют данные одному мастеру (3:1).
Операция выполняется над slice1 параллельного плана запроса.
План запроса в Greengage DB разделен на слайсы (slice), чтобы части плана могли выполняться параллельно на сегментах.
Оценочная стартовая стоимость этого плана — 0.00 (без затрат), а общая стоимость — 431.27.
Планировщик рассчитывает, что запрос вернет одну строку.
Ниже показан тот же запрос с отключенными оценками стоимости:
EXPLAIN (COSTS OFF)
SELECT *
FROM names
WHERE name = 'Joelle';
Результат:
QUERY PLAN
------------------------------------------
Gather Motion 3:1 (slice1; segments: 3)
-> Seq Scan on names
Filter: (name = 'Joelle'::text)
Optimizer: Pivotal Optimizer (GPORCA)
(4 rows)
Тот же запрос в формате JSON:
EXPLAIN (FORMAT JSON)
SELECT *
FROM names
WHERE name = 'Joelle';
Результат:
QUERY PLAN
-------------------------------------------------
[ +
{ +
"Plan": { +
"Node Type": "Gather Motion", +
"Senders": 3, +
"Receivers": 1, +
"Slice": 1, +
"Segments": 3, +
"Gang Type": "primary reader", +
"Startup Cost": 0.00, +
"Total Cost": 431.27, +
"Plan Rows": 1, +
"Plan Width": 58, +
"Plans": [ +
{ +
"Node Type": "Seq Scan", +
"Parent Relationship": "Outer", +
"Slice": 1, +
"Segments": 3, +
"Gang Type": "primary reader", +
"Relation Name": "names", +
"Alias": "names", +
"Startup Cost": 0.00, +
"Total Cost": 431.27, +
"Plan Rows": 1, +
"Plan Width": 58, +
"Filter": "(name = 'Joelle'::text)" +
} +
] +
}, +
"Settings": { +
"Optimizer": "Pivotal Optimizer (GPORCA)"+
} +
} +
]
(1 row)
Если для запроса существует подходящий индекс и условие WHERE может быть использовано для индексного поиска, EXPLAIN может показать другой план.
В следующем примере запрос выполняется с использованием сканирования индекса, а план выводится в формате YAML:
EXPLAIN (FORMAT YAML)
SELECT *
FROM names
WHERE location = 'Sydney, Australia';
Результат:
QUERY PLAN
--------------------------------------------------------------
- Plan: +
Node Type: "Gather Motion" +
Senders: 3 +
Receivers: 1 +
Slice: 1 +
Segments: 3 +
Gang Type: "primary reader" +
Startup Cost: 0.00 +
Total Cost: 10.81 +
Plan Rows: 10000 +
Plan Width: 70 +
Plans: +
- Node Type: "Index Scan" +
Parent Relationship: "Outer" +
Slice: 1 +
Segments: 3 +
Gang Type: "primary reader" +
Scan Direction: "Forward" +
Index Name: "names_idx_loc" +
Relation Name: "names" +
Alias: "names" +
Startup Cost: 0.00 +
Total Cost: 7.77 +
Plan Rows: 10000 +
Plan Width: 70 +
Index Cond: "(location = 'Sydney, Australia'::text)"+
Settings: +
Optimizer: "Pivotal Optimizer (GPORCA)"
(1 row)
Совместимость
Оператор EXPLAIN не определен стандартом SQL.