Анализ запросов
Чтобы проанализировать, как ADQM преобразует и выполняет запросы, используйте выражение EXPLAIN
. Базовый синтаксис:
EXPLAIN [AST | SYNTAX | QUERY TREE | PLAN | PIPELINE | ESTIMATE | TABLE OVERRIDE] [<setting_name> = <setting_value>, ...]
<query_to_analyze>
[FORMAT <output_format>]
где:
-
EXPLAIN [<explain_type>] [<explain_settings>]
— тип анализатораEXPLAIN
(см. таблицу ниже) и соответствующие ему дополнительные настройки; -
<query_to_analyze>
— анализируемый запрос; -
FORMAT <output_format>
— формат вывода результата анализа.
Тип EXPLAIN | Результат выполнения EXPLAIN |
---|---|
Абстрактное синтаксическое дерево запроса |
|
Оптимизированная версия синтаксиса запроса, на которую ADQM заменит исходный текст запроса при его выполнении |
|
Дерево запроса после его оптимизации |
|
План выполнения запроса. Этот тип |
|
Конвейер выполнения запроса |
|
Оценка числа строк, засечек (marks) и кусков данных, которые будут обработаны при выполнении запроса |
|
Предварительная проверка настроек переопределения схемы таблицы для движка баз данных MaterializedMySQL |
EXPLAIN AST
Запрос EXPLAIN AST
выводит абстрактное синтаксическое дерево (Abstract Syntax Tree, AST) анализируемого запроса. Поддерживается для всех типов запросов, не только SELECT
.
Пример
EXPLAIN AST SELECT sum(number) AS test_sums FROM numbers(5) GROUP BY number % 2;
┌─explain─────────────────────────────────────────┐ │ SelectWithUnionQuery (children 1) │ │ ExpressionList (children 1) │ │ SelectQuery (children 3) │ │ ExpressionList (children 1) │ │ Function sum (alias test_sums) (children 1) │ │ ExpressionList (children 1) │ │ Identifier number │ │ TablesInSelectQuery (children 1) │ │ TablesInSelectQueryElement (children 1) │ │ TableExpression (children 1) │ │ Function numbers (children 1) │ │ ExpressionList (children 1) │ │ Literal UInt64_5 │ │ ExpressionList (children 1) │ │ Function modulo (children 1) │ │ ExpressionList (children 2) │ │ Identifier number │ │ Literal UInt64_2 │ └─────────────────────────────────────────────────┘
Параметры
Для запроса EXPLAIN AST
можно использовать опцию graph
, чтобы получить абстрактное синтаксическое дерево в виде графа, описанного на языке DOT. Полученный синтаксис можно загрузить в специальное приложение для отрисовки графов (например, Graphviz — пакет утилит с открытым исходным кодом для автоматической визуализации графов).
Пример построения абстрактного синтаксического дерева в виде графа:
EXPLAIN AST graph=1 SELECT sum(number) AS test_sums FROM numbers(5) GROUP BY number % 2;
┌─explain────────────────────────────────────────────────────────────────────┐ │ digraph { │ │ rankdir="UD"; │ │ n140208872268568[label="SelectWithUnionQuery (children 1)"]; │ │ n140208877065784[label="ExpressionList (children 1)"]; │ │ n140205632168472[label="SelectQuery (children 3)"]; │ │ n140206404082776[label="ExpressionList (children 1)"]; │ │ n140206025898776[label="Function sum (alias test_sums) (children 1)"]; │ │ n140206026032952[label="ExpressionList (children 1)"]; │ │ n140205801742360[label="Identifier number"]; │ │ ... │ │ } │ └────────────────────────────────────────────────────────────────────────────┘
EXPLAIN SYNTAX
При выполнении запросов ADQM может автоматически переписывать их синтаксис для улучшения производительности. Запрос EXPLAIN SYNTAX
позволяет посмотреть применяемые ADQM синтаксические оптимизации — в дальнейшем их можно использовать, чтобы вручную оптимизировать сложные запросы для повышения скорости их выполнения.
Пример
-
Создайте таблицу типа MergeTree и добавьте в нее 1 миллион строк, указав ключ партиционирования так, чтобы данные поделились на 10 партиций:
CREATE TABLE test_table (value UInt64) ENGINE = MergeTree PARTITION BY value % 10 ORDER BY value AS SELECT number FROM numbers(1000000);
-
Выполните запрос, который вычисляет среднее арифметическое по столбцу
value
для первой партиции:SELECT avg(value) FROM (SELECT value FROM test_table) WHERE (value % 10) = 1;
-
В результате выполнения запроса видно, что ADQM обработал только 100 тысяч строк, а не 1 миллион:
┌─avg(value)─┐ │ 499996 │ └────────────┘ 1 row in set. Elapsed: 0.006 sec. Processed 100.00 thousand rows, 800.00 KB (16.40 million rows/s., 131.16 MB/s.)
-
Выполните анализ
EXPLAIN SYNTAX
для приведенного выше запроса:EXPLAIN SYNTAX SELECT avg(value) FROM (SELECT value FROM test_table) WHERE (value % 10) = 1;
В результате этого анализа видно, что ADQM автоматически оптимизировал запрос, переместив фильтр
WHERE
внутрь подзапроса — поэтому достаточно обработать только 1/10 часть данных таблицы:┌─explain────────────────────┐ │ SELECT avg(value) │ │ FROM │ │ ( │ │ SELECT value │ │ FROM test_table │ │ WHERE (value % 10) = 1 │ │ ) │ │ WHERE (value % 10) = 1 │ └────────────────────────────┘
Таким образом можно использовать этот способ оптимизации в более сложных запросах, сразу указывая необходимые фильтры в подзапросах.
EXPLAIN QUERY TREE
Запрос EXPLAIN QUERY TREE
создает дамп дерева запроса. Этот тип анализатора находится в стадии разработки, но его можно использовать в экспериментальном режиме. Для этого перед выполнением запроса необходимо включить опцию: SET allow_experimental_analyzer = 1
.
В примерах запросов EXPLAIN QUERY TREE
, приведенных ниже, используется тестовая таблица с данными о просмотрах страниц, сгенерированными случайным образом. Чтобы воспроизвести эти примеры, создайте предварительно таблицу page_views
:
CREATE TABLE page_views (time DateTime, page_name String, time_on_page UInt64)
ENGINE = MergeTree
ORDER BY time;
INSERT INTO page_views
SELECT
toDate('2023-01-01 00:00:00') + (rand() % 182) AS time,
['landing', 'products', 'docs', 'about'][toInt32(randBinomial(4, 0.01)) + 1],
rand() % 15
FROM numbers(1000000);
Пример
SET allow_experimental_analyzer = 1;
EXPLAIN QUERY TREE
SELECT page_name, toDate(toStartOfMonth(time)) AS month, count() AS page_view_count
FROM page_views
WHERE page_name = 'landing'
GROUP BY page_name, month
ORDER BY page_name, month
LIMIT 3;
┌─explain───────────────────────────────────────────────────────────────────────────────────────────────────┐ │ QUERY id: 0 │ │ PROJECTION COLUMNS │ │ page_name String │ │ month Date │ │ page_view_count UInt64 │ │ PROJECTION │ │ LIST id: 1, nodes: 3 │ │ COLUMN id: 2, column_name: page_name, result_type: String, source_id: 3 │ │ FUNCTION id: 4, function_name: toDate, function_type: ordinary, result_type: Date │ │ ARGUMENTS │ │ LIST id: 5, nodes: 1 │ │ FUNCTION id: 6, function_name: toStartOfMonth, function_type: ordinary, result_type: Date │ │ ARGUMENTS │ │ LIST id: 7, nodes: 1 │ │ COLUMN id: 8, column_name: time, result_type: DateTime, source_id: 3 │ │ FUNCTION id: 9, function_name: count, function_type: aggregate, result_type: UInt64 │ │ JOIN TREE │ │ TABLE id: 3, table_name: default.page_views │ │ WHERE │ │ FUNCTION id: 10, function_name: equals, function_type: ordinary, result_type: UInt8 │ │ ARGUMENTS │ │ LIST id: 11, nodes: 2 │ │ COLUMN id: 2, column_name: page_name, result_type: String, source_id: 3 │ │ CONSTANT id: 12, constant_value: 'landing', constant_value_type: String │ │ GROUP BY │ │ LIST id: 13, nodes: 2 │ │ COLUMN id: 2, column_name: page_name, result_type: String, source_id: 3 │ │ FUNCTION id: 4, function_name: toDate, function_type: ordinary, result_type: Date │ │ ARGUMENTS │ │ LIST id: 5, nodes: 1 │ │ FUNCTION id: 6, function_name: toStartOfMonth, function_type: ordinary, result_type: Date │ │ ARGUMENTS │ │ LIST id: 7, nodes: 1 │ │ COLUMN id: 8, column_name: time, result_type: DateTime, source_id: 3 │ │ ORDER BY │ │ LIST id: 14, nodes: 2 │ │ SORT id: 15, sort_direction: ASCENDING, with_fill: 0 │ │ EXPRESSION │ │ COLUMN id: 2, column_name: page_name, result_type: String, source_id: 3 │ │ SORT id: 16, sort_direction: ASCENDING, with_fill: 0 │ │ EXPRESSION │ │ FUNCTION id: 4, function_name: toDate, function_type: ordinary, result_type: Date │ │ ARGUMENTS │ │ LIST id: 5, nodes: 1 │ │ FUNCTION id: 6, function_name: toStartOfMonth, function_type: ordinary, result_type: Date │ │ ARGUMENTS │ │ LIST id: 7, nodes: 1 │ │ COLUMN id: 8, column_name: time, result_type: DateTime, source_id: 3 │ │ LIMIT │ │ CONSTANT id: 17, constant_value: UInt64_3, constant_value_type: UInt64 │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────┘
РЕКОМЕНДАЦИЯ
Чтобы ускорить выполнение запросов, в которых вычисляются агрегатные значения (как, например, в запросе выше вычисляется количество просмотров страниц по месяцам), можно использовать материализованные представления, автоматически вычисляющие промежуточные агрегатные состояния данных — см. пример в статье Материализованные представления.
|
Параметры
Вывод результата запроса EXPLAIN QUERY TREE
можно настроить с помощью следующих параметров (если значение параметра 1
— соответствующая настройка включена, если 0
— выключена):
-
run_passes
— указывает, выполнять ли все проходы дерева запроса перед созданием дампа дерева запроса (значение по умолчанию —1
); -
passes
— определяет, сколько проходов дерева запроса выполнять (значение по умолчанию —-1
, выполняются все проходы); -
dump_passes
— указывает, выводить ли информацию о выполненных проходах перед созданием дампа дерева запроса (значение по умолчанию —0
).
Cледующий анализ выполняет три прохода дерева запроса и выводит информацию о них перед дампом дерева запроса:
EXPLAIN QUERY TREE passes=3, dump_passes=1
SELECT page_name, toDate(toStartOfMonth(time)) AS month, count() AS page_view_count
FROM page_views
WHERE page_name = 'landing'
GROUP BY page_name, month
ORDER BY page_name, month
LIMIT 3
FORMAT TSVRaw;
Pass 1 QueryAnalysis - Resolve type for each query expression. Replace identifiers, matchers with query expressions. Perform constant folding. Evaluate scalar subqueries. Pass 2 FunctionToSubcolumns - Rewrite function to subcolumns, for example tupleElement(column, subcolumn) into column.subcolumn Pass 3 CountDistinct - Optimize single countDistinct into count over subquery QUERY id: 0 PROJECTION COLUMNS page_name String month Date page_view_count UInt64 PROJECTION LIST id: 1, nodes: 3 COLUMN id: 2, column_name: page_name, result_type: String, source_id: 3 FUNCTION id: 4, function_name: toDate, function_type: ordinary, result_type: Date ARGUMENTS LIST id: 5, nodes: 1 FUNCTION id: 6, function_name: toStartOfMonth, function_type: ordinary, result_type: Date ARGUMENTS LIST id: 7, nodes: 1 COLUMN id: 8, column_name: time, result_type: DateTime, source_id: 3 FUNCTION id: 9, function_name: count, function_type: aggregate, result_type: UInt64 JOIN TREE TABLE id: 3, table_name: default.page_views WHERE FUNCTION id: 10, function_name: equals, function_type: ordinary, result_type: UInt8 ARGUMENTS LIST id: 11, nodes: 2 COLUMN id: 2, column_name: page_name, result_type: String, source_id: 3 CONSTANT id: 12, constant_value: 'landing', constant_value_type: String GROUP BY LIST id: 13, nodes: 2 COLUMN id: 2, column_name: page_name, result_type: String, source_id: 3 FUNCTION id: 4, function_name: toDate, function_type: ordinary, result_type: Date ARGUMENTS LIST id: 5, nodes: 1 FUNCTION id: 6, function_name: toStartOfMonth, function_type: ordinary, result_type: Date ARGUMENTS LIST id: 7, nodes: 1 COLUMN id: 8, column_name: time, result_type: DateTime, source_id: 3 ORDER BY LIST id: 14, nodes: 2 SORT id: 15, sort_direction: ASCENDING, with_fill: 0 EXPRESSION COLUMN id: 2, column_name: page_name, result_type: String, source_id: 3 SORT id: 16, sort_direction: ASCENDING, with_fill: 0 EXPRESSION FUNCTION id: 4, function_name: toDate, function_type: ordinary, result_type: Date ARGUMENTS LIST id: 5, nodes: 1 FUNCTION id: 6, function_name: toStartOfMonth, function_type: ordinary, result_type: Date ARGUMENTS LIST id: 7, nodes: 1 COLUMN id: 8, column_name: time, result_type: DateTime, source_id: 3 LIMIT CONSTANT id: 17, constant_value: UInt64_3, constant_value_type: UInt64
EXPLAIN PLAN
Запрос EXPLAIN PLAN
выводит план выполнения анализируемого запроса в виде дерева, которое показывает в каком порядке будут выполняться выражения запроса. Этапы плана выполнения запроса читаются снизу вверх. Этот тип анализатора используется по умолчанию, если не указан другой тип EXPLAIN
.
Пример
Следующий анализ показывает, что для выполнения запроса SELECT
ADQM сначала считывает данные из таблицы (ReadFromStorage
), затем фильтрует их (Filter
) и после этого агрегирует (Aggregating
).
EXPLAIN SELECT sum(number) AS test_sums FROM numbers(10000) WHERE number > 100 GROUP BY number % 2;
┌─explain─────────────────────────────────────┐ │ Expression ((Projection + Before ORDER BY)) │ │ Aggregating │ │ Expression (Before GROUP BY) │ │ Filter (WHERE) │ │ ReadFromStorage (SystemNumbers) │ └─────────────────────────────────────────────┘
Параметры
В запросах EXPLAIN PLAN
можно использовать следующие параметры, чтобы указать какая информация должна включаться в результат выполняемого анализа (если значение параметра 1
— соответствующая настройка включена, если 0
— выключена):
-
header
— в план выполнения запроса добавляется ключHeader
в виде массива столбцов (выводится название и тип столбца), значения которых вычисляются на каждом шаге.ПримерEXPLAIN header = 0 (по умолчанию) EXPLAIN header = 1 EXPLAIN SELECT sum(number) AS test_sums FROM numbers(5) GROUP BY number % 2;
┌─explain─────────────────────────────────────┐ │ Expression ((Projection + Before ORDER BY)) │ │ Aggregating │ │ Expression (Before GROUP BY) │ │ ReadFromStorage (SystemNumbers) │ └─────────────────────────────────────────────┘
EXPLAIN header = 1 SELECT sum(number) AS test_sums FROM numbers(5) GROUP BY number % 2;
┌─explain─────────────────────────────────────┐ │ Expression ((Projection + Before ORDER BY)) │ │ Header: test_sums UInt64 │ │ Aggregating │ │ Header: modulo(number, 2) UInt8 │ │ sum(number) UInt64 │ │ Expression (Before GROUP BY) │ │ Header: number UInt64 │ │ modulo(number, 2) UInt8 │ │ ReadFromStorage (SystemNumbers) │ │ Header: number UInt64 │ └─────────────────────────────────────────────┘
-
description
— план выполнения запроса включает описание каждого шага.ПримерEXPLAIN description = 0 EXPLAIN description = 1 (по умолчанию) EXPLAIN description = 0 SELECT sum(number) AS test_sums FROM numbers(5) GROUP BY number % 2;
┌─explain───────────────┐ │ Expression │ │ Aggregating │ │ Expression │ │ ReadFromStorage │ └───────────────────────┘
EXPLAIN SELECT sum(number) AS test_sums FROM numbers(5) GROUP BY number % 2;
┌─explain─────────────────────────────────────┐ │ Expression ((Projection + Before ORDER BY)) │ │ Aggregating │ │ Expression (Before GROUP BY) │ │ ReadFromStorage (SystemNumbers) │ └─────────────────────────────────────────────┘
-
indexes
— в план выполнения запроса добавляется ключIndexes
, который содержит массив используемых индексов. Для каждого индекса выводится ключType
(возможные значения:MinMax
,Partition
,PrimaryKey
,Skip
) и дополнительные ключи:-
Name
— имя индекса (выводится только для индексаSkip
); -
Keys
— массив столбцов, используемых индексом; -
Condition
— используемое условие; -
Description
— описание индекса (выводится только для индексаSkip
); -
Parts
— количество кусков данных, отфильтрованных применяемым индексом; -
Granules
— количество гранул, отфильтрованных применяемым индексом.
Этот параметр поддерживается только для анализа запросов, обращающихся к таблицам семейства MergeTree.
ПримерEXPLAIN actions = 0 (default) EXPLAIN actions = 1 EXPLAIN indexes = 0 SELECT sum(value) FROM test_table WHERE (value % 10) = 1;
┌─explain────────────────────────────────────────┐ │ Expression ((Projection + Before ORDER BY)) │ │ Aggregating │ │ Expression (Before GROUP BY) │ │ Filter (WHERE) │ │ ReadFromMergeTree (default.test_table) │ └────────────────────────────────────────────────┘
EXPLAIN indexes = 1 SELECT sum(value) FROM test_table WHERE (value % 10) = 1;
┌─explain────────────────────────────────────────────────────┐ │ Expression ((Projection + Before ORDER BY)) │ │ Aggregating │ │ Expression (Before GROUP BY) │ │ Filter (WHERE) │ │ ReadFromMergeTree (default.test_table) │ │ Indexes: │ │ MinMax │ │ Condition: true │ │ Parts: 10/10 │ │ Granules: 120/120 │ │ Partition │ │ Keys: │ │ moduloLegacy(value, 10) │ │ Condition: (moduloLegacy(value, 10) in [1, 1]) │ │ Parts: 1/10 │ │ Granules: 12/120 │ │ PrimaryKey │ │ Condition: true │ │ Parts: 1/1 │ │ Granules: 12/12 │ └────────────────────────────────────────────────────────────┘
-
-
actions
— в план выполнения запроса добавляется подробная информация о действиях, выполняемых на каждом шаге (ключActions
).ПримерEXPLAIN actions = 0 (по умолчанию) EXPLAIN actions = 1 EXPLAIN SELECT sum(number) AS test_sums FROM numbers(5) GROUP BY number % 2;
┌─explain─────────────────────────────────────┐ │ Expression ((Projection + Before ORDER BY)) │ │ Aggregating │ │ Expression (Before GROUP BY) │ │ ReadFromStorage (SystemNumbers) │ └─────────────────────────────────────────────┘
EXPLAIN actions = 1 SELECT sum(number) AS test_sums FROM numbers(5) GROUP BY number % 2;
┌─explain─────────────────────────────────────────────────────────────────────────┐ │ Expression ((Projection + Before ORDER BY)) │ │ Actions: INPUT : 0 -> sum(number) UInt64 : 0 │ │ ALIAS sum(number) :: 0 -> test_sums UInt64 : 1 │ │ Positions: 1 │ │ Aggregating │ │ Keys: modulo(number, 2) │ │ Aggregates: │ │ sum(number) │ │ Function: sum(UInt64) → UInt64 │ │ Arguments: number │ │ Skip merging: 0 │ │ Expression (Before GROUP BY) │ │ Actions: INPUT : 0 -> number UInt64 : 0 │ │ COLUMN Const(UInt8) -> 2 UInt8 : 1 │ │ FUNCTION modulo(number : 0, 2 :: 1) -> modulo(number, 2) UInt8 : 2 │ │ Positions: 0 2 │ │ ReadFromStorage (SystemNumbers) │ └─────────────────────────────────────────────────────────────────────────────────┘
-
json
— план выполнения запроса выводится в формате JSON. Каждый узел — это словарь, в котором всегда есть ключиNode Type
(название шага) иPlans
(массив с описаниями дочерних шагов). Другие дополнительные ключи могут быть добавлены в зависимости от типа узла и настроек.Чтобы избежать ненужного экранирования, рекомендуется использовать формат TSVRaw для вывода результата анализа.
ПримерEXPLAIN json = 0 (по умолчанию) EXPLAIN json = 1 EXPLAIN SELECT sum(number) AS test_sums FROM numbers(5) GROUP BY number % 2;
┌─explain─────────────────────────────────────┐ │ Expression ((Projection + Before ORDER BY)) │ │ Aggregating │ │ Expression (Before GROUP BY) │ │ ReadFromStorage (SystemNumbers) │ └─────────────────────────────────────────────┘
EXPLAIN json = 1 SELECT sum(number) AS test_sums FROM numbers(5) GROUP BY number % 2 FORMAT TSVRaw;
[ { "Plan": { "Node Type": "Expression", "Description": "(Projection + Before ORDER BY)", "Plans": [ { "Node Type": "Aggregating", "Plans": [ { "Node Type": "Expression", "Description": "Before GROUP BY", "Plans": [ { "Node Type": "ReadFromStorage", "Description": "SystemNumbers" } ] } ] } ] } } ]
EXPLAIN PIPELINE
Запрос EXPLAIN PIPELINE
выводит конвейер выполнения запроса, который показывает сколько параллельных потоков используется для выполнения каждого шага плана запроса.
Пример
EXPLAIN PIPELINE SELECT sum(number) AS test_sums FROM numbers(5) GROUP BY number % 2;
┌─explain───────────────────┐ │ (Expression) │ │ ExpressionTransform × 8 │ │ (Aggregating) │ │ Resize 1 → 8 │ │ AggregatingTransform │ │ (Expression) │ │ ExpressionTransform │ │ (ReadFromStorage) │ │ Limit │ │ Numbers 0 → 1 │ └───────────────────────────┘
Параметры
Вывод результата выполнения запроса EXPLAIN PIPELINE
можно настраивать с помощью следующих параметров (если значение параметра 1
— настройка включена, если 0
— выключена):
-
header
— выводится заголовок для каждого выходного порта (значение по умолчанию —0
).ПримерEXPLAIN PIPELINE header = 1 SELECT sum(number) AS test_sums FROM numbers(5) GROUP BY number % 2;
┌─explain─────────────────────────────────────────────────────────────────────────┐ │ (Expression) │ │ ExpressionTransform × 8 │ │ Header: test_sums UInt64: test_sums UInt64 UInt64(size = 0) │ │ (Aggregating) │ │ Resize 1 → 8 │ │ Header × 8 : modulo(number, 2) UInt8: modulo(number, 2) UInt8 UInt8(size = 0) │ │ sum(number) UInt64: sum(number) UInt64 UInt64(size = 0) │ │ AggregatingTransform │ │ Header: modulo(number, 2) UInt8: modulo(number, 2) UInt8 UInt8(size = 0) │ │ sum(number) UInt64: sum(number) UInt64 UInt64(size = 0) │ │ (Expression) │ │ ExpressionTransform │ │ Header: number UInt64: number UInt64 UInt64(size = 0) │ │ modulo(number, 2) UInt8: modulo(number, 2) UInt8 UInt8(size = 0) │ │ (ReadFromStorage) │ │ Limit │ │ Header: number UInt64: number UInt64 UInt64(size = 0) │ │ Numbers 0 → 1 │ │ Header: number UInt64: number UInt64 UInt64(size = 0) │ └─────────────────────────────────────────────────────────────────────────────────┘
-
graph
— конвейер выполнения запроса выводится в виде описанного на языке DOT графа (значение по умолчанию —0
). Полученный синтаксис можно загрузить в приложение для визуализации графов (например, Graphviz).ПримерEXPLAIN PIPELINE graph = 1 SELECT sum(number) AS test_sums FROM numbers(5) GROUP BY number % 2 FORMAT TSV;
digraph { rankdir="LR"; { node [shape = rect] subgraph cluster_0 { label ="Expression"; style=filled; color=lightgrey; node [style=filled,color=white]; { rank = same; n6 [label="ExpressionTransform × 8"]; } } subgraph cluster_1 { label ="ReadFromStorage"; style=filled; color=lightgrey; node [style=filled,color=white]; { rank = same; n2 [label="Limit"]; n1 [label="Numbers"]; } } subgraph cluster_2 { label ="Expression"; style=filled; color=lightgrey; node [style=filled,color=white]; { rank = same; n3 [label="ExpressionTransform"]; } } subgraph cluster_3 { label ="Aggregating"; style=filled; color=lightgrey; node [style=filled,color=white]; { rank = same; n4 [label="AggregatingTransform"]; n5 [label="Resize"]; } } } n2 -> n3 [label=""]; n1 -> n2 [label=""]; n3 -> n4 [label=""]; n4 -> n5 [label=""]; n5 -> n6 [label="× 8"]; }
-
compact
— если включена настройкаgraph
, граф выводится в компактном режиме (значение по умолчанию —1
).ПримерEXPLAIN PIPELINE graph = 1, compact = 0 SELECT sum(number) AS test_sums FROM numbers(5) GROUP BY number % 2 FORMAT TSV;
digraph { rankdir="LR"; { node [shape = rect] n140206024061464[label="Numbers"]; n140205465170584[label="Limit"]; n140205620507928[label="ExpressionTransform"]; n140205801688600[label="AggregatingTransform"]; n140205649781464[label="Resize"]; n140205630520728[label="ExpressionTransform"]; n140205788048536[label="ExpressionTransform"]; n140205620512152[label="ExpressionTransform"]; n140206023882392[label="ExpressionTransform"]; n140206024060696[label="ExpressionTransform"]; n140205620509080[label="ExpressionTransform"]; n140205717371544[label="ExpressionTransform"]; n140206023882008[label="ExpressionTransform"]; } n140206024061464 -> n140205465170584; n140205465170584 -> n140205620507928; n140205620507928 -> n140205801688600; n140205801688600 -> n140205649781464; n140205649781464 -> n140205630520728; n140205649781464 -> n140205788048536; n140205649781464 -> n140205620512152; n140205649781464 -> n140206023882392; n140205649781464 -> n140206024060696; n140205649781464 -> n140205620509080; n140205649781464 -> n140205717371544; n140205649781464 -> n140206023882008; }
EXPLAIN ESTIMATE
Анализ с помощью запроса EXPLAIN ESTIMATE
показывает предполагаемое количество строк, засечек и кусков данных, которые необходимо считать из таблицы при обработке запроса. Этот тип анализа можно применять только к запросам, обращающимся к таблицам семейства MergeTree.
Пример
-
Создайте таблицу MergeTree, используя специальные опции, чтобы настроить деление кусков данных на гранулы:
-
index_granularity
— задает максимальное количество строк данных между засечками индекса; -
write_final_mark
— указывает, записывать ли последнюю засечку индекса в конце куска данных, указывающую на последний байт.
CREATE TABLE test_table_estimate (i Int64) ENGINE = MergeTree ORDER BY i SETTINGS index_granularity = 16, write_final_mark = 0;
-
-
Вставьте данные в таблицу, повторив следующую команду три раза:
INSERT INTO test_table_estimate SELECT number FROM numbers(128);
-
Выполните анализ запроса для чтения данных из таблицы:
EXPLAIN ESTIMATE SELECT * FROM test_table_estimate;
Результат анализа:
┌─database─┬─table───────────────┬─parts─┬─rows─┬─marks─┐ │ default │ test_table_estimate │ 3 │ 384 │ 24 │ └──────────┴─────────────────────┴───────┴──────┴───────┘
EXPLAIN TABLE OVERRIDE
Запрос EXPLAIN TABLE OVERRIDE
позволяет предварительно проверить корректность конфигураций для переопределения схемы таблицы, которые можно указать при создании базы данных типа MaterializedMySQL (см. Table Overrides). Если переопределение схемы таблицы может привести к какой-либо ошибке, будет выведено соответствующее сообщение (например, при использовании столбцов типа Nullable для выражений PARTITION BY
и ORDER BY
, для которых это не рекомендуется).
Для выполнения запроса EXPLAIN TABLE OVERRIDE
подключение к таблице на удаленном сервере MySQL осуществляется через табличную функцию mysql.
Пример
-
На удаленном сервере MySQL создайте таблицу в базе данных
mysql_db
:CREATE TABLE mysql_table (id INT PRIMARY KEY, date DATETIME DEFAULT now());
-
В ADQM выполните следующий запрос, чтобы проверить корректность партиционирование таблицы по столбцу
date
(замените<host>:<port>
на адрес сервера MySQL, а<user_name>
и<user_password>
на имя пользователя и пароль для доступа к базе данных MySQL):EXPLAIN TABLE OVERRIDE mysql('<host>:<port>', 'mysql_db', 'mysql_table', '<user_name>', '<user_password>') PARTITION BY toYYYYMM(date);
В результате выполнения запроса будет выведено исключение с рекомендацией, как можно исправить переопределение ключа партиционирования:
Exception: PARTITION BY override refers to nullable column `date` (use assumeNotNull() if the column does not in fact contain NULL values). (INVALID_TABLE_OVERRIDE) ....`
-
Измените переопределение
PARTITION BY
в соответствии с указанной рекомендацией:EXPLAIN TABLE OVERRIDE mysql('<host>:<port>', 'mysql_db', 'mysql_table', 'root', 'my-secret-pw') PARTITION BY toYYYYMM(assumeNotNull(date));
Вывод:
┌─explain──────────────────────────────────────────────┐ │ PARTITION BY uses columns: `date` Nullable(DateTime) │ └──────────────────────────────────────────────────────┘