EXPLAIN Statement
Shows the execution plan of a statement.
Syntax:
Example:
EXPLAIN Types
AST— Abstract syntax tree.SYNTAX— Query text after AST-level optimizations.QUERY TREE— Query tree after Query Tree level optimizations.PLAN— Query execution plan.PIPELINE— Query execution pipeline.
EXPLAIN AST
Dump query AST. Supports all types of queries, not only SELECT.
Settings:
graph– Prints AST as a graph described in the DOT graph description language. Default: 0.
Examples:
EXPLAIN SYNTAX
Shows the Abstract Syntax Tree (AST) of a query after syntax analysis.
It's done by parsing the query, constructing query AST and query tree, optionally running query analyzer and optimization passes, and then converting the query tree back to the query AST.
Settings:
oneline– Print the query in one line. Default:0.run_query_tree_passes– Run query tree passes before dumping the query tree. Default:0.query_tree_passes– Ifrun_query_tree_passesis set, specifies how many passes to run. Without specifyingquery_tree_passesit runs all the passes.
Examples:
Output:
With run_query_tree_passes:
Output:
EXPLAIN QUERY TREE
Settings:
run_passes— Run all query tree passes before dumping the query tree. Default:1.dump_passes— Dump information about used passes before dumping the query tree. Default:0.passes— Specifies how many passes to run. If set to-1, runs all the passes. Default:-1.dump_tree— Display the query tree. Default:1.dump_ast— Display the query AST generated from the query tree. Default:0.
Example:
EXPLAIN PLAN
Dump query plan steps.
Settings:
optimize— Controls whether query plan optimizations are applied before displaying the plan. Default: 1.header— Prints output header for step. Default: 0.description— Prints step description. Default: 1.indexes— Shows used indexes, the number of filtered parts and the number of filtered granules for every index applied. Default: 0. Supported for MergeTree tables. Starting from ClickHouse >= v25.9, this statement only shows reasonable output when used withSETTINGS use_query_condition_cache = 0, use_skip_indexes_on_data_read = 0.projections— Shows all analyzed projections and their effect on part-level filtering based on projection primary key conditions. For each projection, this section includes statistics such as the number of parts, rows, marks, and ranges that were evaluated using the projection's primary key. It also shows how many data parts were skipped due to this filtering, without reading from the projection itself. Whether a projection was actually used for reading or only analyzed for filtering can be determined by thedescriptionfield. Default: 0. Supported for MergeTree tables.actions— Prints detailed information about step actions. Default: 0.sorting— Prints the sort description for each plan step that produces sorted output. Default: 0.keep_logical_steps— Keeps logical plan steps for joins instead of converting them to physical join implementations. Default: 0.json— Prints query plan steps as a row in JSON format. Default: 0. It is recommended to use TabSeparatedRaw (TSVRaw) format to avoid unnecessary escaping.input_headers— Prints input headers for step. Default: 0. Mostly useful only for developers to debug issues related to input-output header mismatch.column_structure— Prints also the structure of columns in headers on top of their name and type. Default: 0. Mostly useful only for developers to debug issues related to input-output header mismatch.distributed— Shows query plans executed on remote nodes for distributed tables or parallel replicas. Default: 0.compact— When enabled, hides expression steps and detailed action info (inputs, functions, aliases, and output positions) from the plan. Only has an effect when actions = 1. Default: 0.pretty— Prints the plan tree using line-drawing characters (├──, └──, │) instead of indentation to visualize the hierarchy. Also formats join step properties inline. Default: 0.
When json=1 step names will contain an additional suffix with unique step identifier.
Example:
Step and query cost estimation is not supported.
When json = 1, the query plan is represented in JSON format. Every node is a dictionary that always has the keys Node Type and Plans. Node Type is a string with a step name. Plans is an array with child step descriptions. Other optional keys may be added depending on node type and settings.
Example:
With description = 1, the Description key is added to the step:
With header = 1, the Header key is added to the step as an array of columns.
Example:
With indexes = 1, the Indexes key is added. It contains an array of used indexes. Each index is described as JSON with Type key (a string Partition Min-Max, Partition, Statistics, PrimaryKey or Skip) and optional keys:
Name— The index name (currently only used forSkipindexes).Keys— The array of columns used by the index.Condition— The used condition.Description— The index description (currently only used forSkipindexes).Parts— The number of parts after/before the index is applied.Granules— The number of granules after/before the index is applied.Ranges— The number of granules ranges after the index is applied.
Example:
With projections = 1, the Projections key is added. It contains an array of analyzed projections. Each projection is described as JSON with following keys:
Name— The projection name.Condition— The used projection primary key condition.Description— The description of how the projection is used (e.g. part-level filtering).Selected Parts— Number of parts selected by the projection.Selected Marks— Number of marks selected.Selected Ranges— Number of ranges selected.Selected Rows— Number of rows selected.Filtered Parts— Number of parts skipped due to part-level filtering.
Example:
With actions = 1, added keys depend on step type.
Example:
With compact = 1, each Expression step is removed. Along with that, if actions = 1 is set, then Actions and Positions lines are hidden, leaving only the step descriptions:
With distributed = 1, the output includes not only the local query plan but also the query plans that will be executed on remote nodes. This is useful for analyzing and debugging distributed queries.
Example with distributed table:
Example with parallel replicas:
In both examples, the query plan shows the complete execution flow including local and remote steps.
With pretty = 1, the plan tree is displayed using line-drawing characters instead of indentation, and additional information is shown for key steps:
- Query output columns are printed at the top of the plan.
- Expressions in filters, aggregation keys, sort descriptions, and window functions are displayed in human-readable SQL-like notation (e.g.,
a + 1 > 5instead ofgreater(plus(a, 1), 5)). Internal column identifier prefixes (such as__table1.) are removed for clarity. - Source steps (such as
ReadFromMergeTree) display their output columns. - Filter steps display the filter condition in SQL notation. When runtime join filters are present, they are shown separately.
- Aggregation steps display keys and aggregate functions with their arguments (e.g.,
sum(c),count()). - IN sets from tuple literals show their values (truncated for large sets), subquery-based sets are labeled
subquery1,subquery2, etc., and sets fromSetengine tables show the table name. - Join steps display the join relation using mathematical notation, estimated result row count, and which output columns come from the left vs. right side. The following symbols are used to represent different join types:
| Symbol | Join Type |
|---|---|
⋈ | Inner Join |
⟕ | Left Join |
⟖ | Right Join |
⟗ | Full Join |
⋉ | Left Semi Join |
⋊ | Right Semi Join |
⋉ with strikethrough | Left Anti Join |
⋊ with strikethrough | Right Anti Join |
× | Cross Join |
For example, t1 ⟕ t2 means a left join between tables t1 and t2.
The number in brackets after the table name (e.g., t1[100]) indicates the estimated row count
when table statistics are available.
The pretty option works well together with compact = 1, which hides Expression steps and detailed action info, making the plan easier to read.
A more detailed example with joins:
EXPLAIN PIPELINE
Settings:
header— Prints header for each output port. Default: 0.graph— Prints a graph described in the DOT graph description language. Default: 0.compact— Prints graph in compact mode ifgraphsetting is enabled. Default: 1.
When compact=0 and graph=1 processor names will contain an additional suffix with unique processor identifier.
Example:
EXPLAIN ESTIMATE
Shows the estimated number of rows, marks and parts to be read from the tables while processing the query. Works with tables in the MergeTree family.
Example
Creating a table:
Query:
Result:
EXPLAIN TABLE OVERRIDE
Shows the result of a table override on a table schema accessed through a table function. Also does some validation, throwing an exception if the override would have caused some kind of failure.
Example
Assume you have a remote MySQL table like this:
Result:
The validation is not complete, so a successful query does not guarantee that the override would not cause issues.