TheDocumentation Index
Fetch the complete documentation index at: https://docs.firebolt.io/llms.txt
Use this file to discover all available pages before exploring further.
EXPLAIN feature analyzes and displays how Firebolt’s query processing system runs your query. You can use this information to understand resource utilization, and identify opportunities to improve and optimize your query performance.
If you specify the ANALYZE option for EXPLAIN, Firebolt also collects detailed metrics about each operator during query runtime, including the amount of time spent on the operator, and how much data it processes.
Syntax
| Parameter | Description |
|---|---|
option_name | The name of an option. See below for a list of all available options. |
option_value | The value of the option. If no value is specified, the default is TRUE. |
<statement> | Any statement. |
Explain Options
You can augment the output ofEXPLAIN by specifying options. The following table lists all available options and their functionalities:
| Option Name | Option Values | Description |
|---|---|---|
LOGICAL | TRUE, FALSE | Returns the optimized logical query plan by default, unless otherwise specified. |
PHYSICAL | TRUE, FALSE | Returns an optimized physical query plan containing shuffle operators for queries on distributed engines, showing how work is distributed between nodes of an engine. |
ANALYZE | TRUE, FALSE | Returns an optimized physical query plan annotated with metrics from query execution. For more information about these metrics, see Example with ANALYZE. |
ALL | TRUE, FALSE | Returns all of the previous LOGICAL, PHYSICAL, and ANALYZE plans. Use the following sample syntax: EXPLAIN (ALL) <select statement>. |
STATISTICS | TRUE, FALSE | Returns an annotated query plan that includes estimates from Firebolt’s query optimizer. This option works with LOGICAL, PHYSICAL, ANALYZE, and ALL. Use the following sample syntax: EXPLAIN (STATISTICS) <select statement>. |
FORMAT | TEXT, JSON | Changes the result format of the EXPLAIN command. TEXT is optimized for humans and LLMs. JSON makes it easy to work with the plans programmatically. |
LOGICAL, PHYSICAL, ANALYZE, and ALL. If you need to view several plans at once, use the ALL option.
All examples in this section were run on Firebolt version
4.26.0, on a two-node M storage-optimized engine.
The underlying dataset is TPC-H at scale factor 100. The lineitem table contains 77GiB of uncompressed data.Basic Example
The following example shows how to generate anEXPLAIN statement for a SELECT query on a table named lineitem.
EXPLAIN output shows the sequence of operations that Firebolt’s engine will use to run the query:
- Read the required columns from the
lineitemtable. - Filter the
lineitemtable by theWHEREconditions. - Remove the columns that are no longer required.
- Perform the aggregation as specified by the
GROUP BYclause. - Sort resulting rows in ascending order by all columns from the
ORDER BYclause. - Bring the columns into the order specified in the
SELECTclause.
Example with ALL
The following code example runs the same query as the previous example on a multi-node engine using the(ALL) option, which is the same as specifying (ALL TRUE) or (LOGICAL, PHYSICAL, ANALYZE).
The query returns three columns explain_logical, explain_physical, and explain_analyze.
Each column can be toggled on or off using the corresponding options.
For example, to display only explain_logical and explain_analyze, you can specify either (LOGICAL, ANALYZE) or (ALL, PHYSICAL FALSE).
With the ANALYZE option enabled, this query took 2.5 seconds to run.
Without the ANALYZE option, the query is only planned and should return the result almost immediately.
- The
LOGICALplan shows the optimized logical query plan of theSELECTstatement. Additionally, it shows the output row type for each operator. For operators with multiple input operators such as theJoinoperator, input columns are concatenated. For example, if the first input produces three columns, and the second input produces four columns, the join produces seven columns. - The
PHYSICALplan shows a detailed, optimized physical plan that includes Shuffle operators for distributed query execution, offering insights into how tasks are distributed across the engine’s nodes. AShuffleoperator redistributes data across engine nodes. For example, scans ofFACTtables, like operator[10] [TableFuncScan], and the operators following it are automatically distributed across all nodes of an engine. AShuffleoperator of typeHashindicates that the workload of the following operators is distributed across all nodes, while aShuffleoperator of typeGatherconsolidates data onto a single node of the engine. In the previous example, only the operator[2] [SortMerge]runs on a single node, merging the sorted partial query results from all other nodes. TheMaybeCacheoperator, at the top of the plan, caches its input in main memory on a best-effort basis for future runs of the same (sub-) query. It considers the entire plan leading to its input, as well as the state of the scanned tables. If the data in a table changes, theMaybeCacheoperator will know not to read an outdated cached entry. It may also skip caching large results or prioritize caching results that offer greater time savings. TheMaybeCacheoperator may appear in different places of a plan, but in this query it caches the full query result. For more information about theMaybeCacheoperator, see Subresult Reuse in Firebolt. - The
ANALYZEplan contains the same plan shape as thePHYSICALexplain, but annotated with metrics collected during query execution. For each operator, it shows the number of rows it produced inoutput_cardinality, and how much time was spent on that operator inthread_timeandcpu_time. Thethread_timeis the sum of the wall-clock time that threads spent working on the operator across all nodes, whilecpu_timeis the total time those threads were scheduled on a CPU core. A significantly smallercpu_timecompared tothread_timesuggests that the operator is either waiting on input or output operations or that the engine is handling multiple queries simultaneously. ForTableFuncScanoperators that read from managed tables, additional metrics may be displayed:granulesshows the output granules (not pruned) out of the total number of granules that were considered. This helps you understand the effectiveness of primary index pruning in reducing the amount of data scanned during query execution. In the example above,granules: 80577/80577indicates that no granules were pruned by the primary index, meaning all 80,577 granules were scanned.cardinality_before_prewheremeasures the number of rows selected for scanning after tablet and granule pruning. After this static pruning step, prewhere optimizes scanning by reading columns with the most selective predicates first. By evaluating these predicates early, the scan can perform a second pruning pass, excluding additional granules from being read for the remaining columns. If the ratiocardinality_before_prewhere / output_cardinalityis large, it indicates that prewhere was effective in eliminating additional rows before the main scan.
Analyzing the Metrics
In the previous example, thecpu_time is almost as high as the thread_time on the TableFuncScan node. This indicates that the data of the lineitem table was in the SSD cache.
On a cold query run, where data must be retrieved from an Amazon S3 bucket, thread_time is considerably higher than cpu_time for the same operator:
Example with STATISTICS
The following code example uses theSTATISTICS option to display the logical and physical query plan for the SELECT statement, annotated with estimated statistics from Firebolt’s query optimizer:
Each plan node is annotated with a [Logical Profile], indicating the source of the estimation for that node as well as the row count estimate.
| Source | Description |
|---|---|
hardcoded | This node received hard-coded defaults because no additional information is available, a scenario that typically occurs only with external tables. |
estimated | This node’s profile was computed from its child nodes’ profiles, based on assumptions about the data that may not always hold true. These assumptions can introduce inaccuracies, which may be further amplified. |
metadata | This node’s profile was constructed from available metadata, ensuring that the information is either precise or highly accurate. |
history | This node’s profile was obtained from a previously recorded run, and is accurate unless data has changed since the recording. |
learned | This node’s profile was predicted using machine learning. |
Example with FORMAT
The following example uses theFORMAT option to query telemetry in different ways.
The TEXT format makes it easy to understand telemetry for humans and LLMs.
As options are fully composable, it can be combined with other options such as ANALYZE.
- Most time is spent in the
INNER JOIN(776ms thread time). After that, theconcatprojection is the second most expensive operation (286ms thread time). - The
MATERIALIZEDCTE led to the planner adding theLoopbackshuffle. This way, the result of Node[6]can be consumed multiple times. TheRecurring Nodeat the bottom of the plan shows the second timemat_ctegets consumed. - The probe side of the join terminates early due to the
LIMITon top. Only around 590k rows make it out of the projection in Node[5].
JSON telemetry is easy:
- The
JSONformat contains telemetry for all operators under theoperatorsarray. - Every operator has a unique
operator_id. - Navigating the operator DAG can be done through the
input_idsattached to each node. The DAG’s root operator id is stored in the top-levelroot_operator_id. - Every operator can have
annotations. WhenANALYZEis selected as an option, these containexecution_metrics.