Перейти к содержанию

EXPLAIN

Для анализа производительности запросов в Picodata можно использовать команду EXPLAIN, с помощью которой можно узнать, как будет выглядеть план исполнения запроса. План позволяет наглядно оценить структуру и последовательность действий при выполнении запроса.

В реализацию EXPLAIN заложены следующие принципы:

Синтаксис

EXPLAIN ( facet FMT VERBOSE , ) dml dql

Фасеты (режимы отображения)

RAW BUCKETS LOGICAL FORWARD CONTEXT

Команда EXPLAIN позволяет указывать определенные режимы вывода EXPLAIN, также называемые фасетами. В настоящий момент можно указывать фасеты RAW, LOGICAL, BUCKETS, FORWARD и CONTEXT в любом порядке. Каждый фасет отвечает за конкретную информацию о запросе.

При указании нескольких фасетов одновременно также печатаются их заголовки, позволяющие быстро ориентироваться в выводе. Например:

EXPLAIN (LOGICAL, BUCKETS) SELECT name, id FROM _pico_table;
──────────────────────────────────────────────────────────────────────
 # Logical plan                                                       
──────────────────────────────────────────────────────────────────────

projection (_pico_table.name::text -> name, _pico_table.id::int -> id)
  scan _pico_table

──────────────────────────────────────────────────────────────────────
 # Buckets                                                            
──────────────────────────────────────────────────────────────────────

buckets = any

Если для EXPLAIN не указано ни одного фасета, то фасетами по умолчанию являются LOGICAL и BUCKETS. Таким образом, запросы

EXPLAIN (LOGICAL, BUCKETS) SELECT name, id FROM _pico_table;

и

EXPLAIN SELECT name, id FROM _pico_table;

эквивалентны.

С подробным описанием каждого фасета EXPLAIN можно ознакомиться тут:

  • RAW — низкоуровневый план исполнения запроса.
  • LOGICAL — высокоуровневый план исполнения запроса.
  • BUCKETS — информация о бакетах, участвующих в исполнении запроса.
  • FORWARD — анализ сетевых пересылок, необходимых для исполнения запроса.
  • CONTEXT — прочие переменные среды, влияющие на исполнение запроса.

Достоверность плана

Команда EXPLAIN в Picodata показывает полный план запроса — со всеми операциями, которые реально выполняются, даже если они не следуют напрямую из текста запроса. Например, COUNT(*) в Picodata исполняется путем частичного подсчета на узлах хранения и финального суммирования результатов. Это следует из вывода фасета LOGICAL:

EXPLAIN (LOGICAL) SELECT COUNT(*) FROM t;
projection (sum(count_1::int::int)::int::int -> col_1)
  motion [policy: full, program: ReshardIfNeeded]
    projection (count(*)::int -> count_1)
      scan t

Узел motion отражает перераспределение данных между узлами кластера. Подробнее об этом можно почитать здесь.

Возможность применения к проблемным запросам

Важной особенностью EXPLAIN в Picodata является возможность получить EXPLAIN для запросов, которые приводят к ошибке при исполнении. Так, Picodata всегда старается построить EXPLAIN для синтаксически корректных запросов, даже если они семантически некорректные. Например:

SELECT name, id FROM _pico_table WHERE MAX(id) = 5;
ERROR:  Query 1 from EXPLAIN (RAW): Failed to compile SQL statement: misuse of aggregate function MAX()

Тем не менее, Picodata выполнит EXPLAIN от такого запроса:

EXPLAIN (RAW) SELECT name, id FROM _pico_table WHERE MAX(id) = 5;
╭───────────────────╮
│ 1. Query (ROUTER) │
╰───────────────────╯

SELECT "_pico_table"."name", "_pico_table"."id" FROM "_pico_table" WHERE max ("_pico_table"."id"::int) = 5::int

plan:
Failed to compile SQL statement: misuse of aggregate function MAX()

На данный момент у возможности построить EXPLAIN для проблемных запросов есть ограничения:

  • Нельзя получить EXPLAIN для запроса с транзакционным блоком, если он затрагивает более одного бакета.

Возможности форматирования

В Picodata для EXPLAIN также существует опция FMT, которая применяется к фасетам. В случае LOGICAL форматирование применяется к плану. В случае RAW форматирование применяется к локальным SQL-запросам и их планам. В случае BUCKETS список бакетов разбивается на строки, но только вместе с опцией VERBOSE. Ниже приведены примеры.

Пример с LOGICAL:

EXPLAIN (LOGICAL) SELECT id, item FROM warehouse;
projection (warehouse.id::int -> id, warehouse.item::text -> item)
  scan warehouse

При указании опции FMT вывод форматируется:

EXPLAIN (LOGICAL, FMT) SELECT id, item FROM warehouse;
projection (
  warehouse.id::int -> id,
  warehouse.item::text -> item
)
  scan warehouse

Пример с RAW:

EXPLAIN (RAW) SELECT * FROM warehouse;
╭──────────────────────────╮
│ 1. Query (WHOLE STORAGE) │
╰──────────────────────────╯

SELECT "warehouse"."id", "warehouse"."item", "warehouse"."type" FROM "warehouse"

plan:
    [0] SCAN TABLE warehouse (~1048576 rows)

При указании опции FMT вывод будет отформатирован:

EXPLAIN (RAW, FMT) SELECT * FROM warehouse;
╭──────────────────────────╮
│ 1. Query (WHOLE STORAGE) │
╰──────────────────────────╯

SELECT
  "warehouse"."id",
  "warehouse"."item",
  "warehouse"."type"
FROM
  "warehouse"

plan:
    [0] SCAN TABLE warehouse (~1048576 rows)

Пример с BUCKETS (опция VERBOSE выводит список бакетов целиком):

EXPLAIN (BUCKETS, VERBOSE) SELECT * FROM warehouse
WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
             13, 14, 15, 16);
buckets = [219, 626, 653, 799, 1403, 1410, 1418, 1860, 1934, 1948, 1958, 2564, 2640, 2752, 2802, 2852]

При указании опции FMT список бакетов будет отформатирован:

EXPLAIN (BUCKETS, VERBOSE, FMT) SELECT * FROM warehouse
WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
             13, 14, 15, 16);
buckets = [
  219, 626, 653, 799, 1403, 1410, 1418, 1860,
  1934, 1948, 1958, 2564, 2640, 2752, 2802,
  2852
]

Списки, которые умещаются в одну строку, не разбиваются.

Опцию FMT полезно использовать при анализе вывода EXPLAIN для сложных запросов. В будущем могут быть добавлены как новые фасеты, так и новые способы форматирования их элементов.

Подробный вывод

Для EXPLAIN также существует опция VERBOSE, которая управляет полнотой вывода фасетов. В настоящий момент она применяется только к фасету BUCKETS. По умолчанию этот фасет выводит лишь начало списка бакетов — столько элементов, сколько умещается в одну строку, — и указывает, сколько бакетов осталось за ними. Опция VERBOSE выводит список целиком. Ниже приведен пример.

Пример с BUCKETS:

EXPLAIN (BUCKETS) SELECT * FROM warehouse
WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
             13, 14, 15, 16);
buckets = [219, 626, 653, 799, 1403, ... (11 more)]

При указании опции VERBOSE список бакетов выводится целиком:

EXPLAIN (BUCKETS, VERBOSE) SELECT * FROM warehouse
WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
             13, 14, 15, 16);
buckets = [219, 626, 653, 799, 1403, 1410, 1418, 1860, 1934, 1948, 1958, 2564, 2640, 2752, 2802, 2852]

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