Execution plan display (EXPLAIN)

2023-08-18 09:26:34  Updated

The EXPLAIN command displays the logical execution plan generated by the optimizer for a given SQL statement.

When the EXPLAIN command is run, the system generates a logical execution plan for the given SQL statement and displays the plan to the user. However, the system does not generate a physical execution plan (executable code), nor does it actually execute the plan or put the plan into the plan cache.

The display of the SQL execution plan is key to understanding the SQL execution logic and performance optimization.

Syntax of the EXPLAIN command

The EXPLAIN command has three options: BASIC, EXTENDED, and PARTITIONS. The level of detail in the information displayed is different.

Use the following command syntax:

EXPLAIN [BASIC | EXTENDED | PARTITIONS | FORMAT = format_name] explainable_stmt

format_name: { TRADITIONAL | JSON }

explainable_stmt: { SELECT statement 
                   | DELETE statement 
                    | INSERT statement 
                    | REPLACE statement 
                    | UPDATE statement }

Shape and operators of a plan

The first part of the output of the EXPLAIN command is a tree-like structure representing the execution plan. The hierarchy of each operation in the tree is represented by the indentation of its operator. Example execution plan:

|==========================================
|ID|OPERATOR         |NAME|EST. ROWS|COST|
------------------------------------------
|0 |SORT             |    |1        |2763|
|1 | MERGE INNER JOIN|    |1        |2735|
|2 |  SORT           |    |1000     |1686|
|3 |   TABLE SCAN    |t2  |1000     |1180|
|4 |  TABLE SCAN     |t1  |1        |815 |
==========================================

The following figure shows the tree-like structure of the execution plan.

p167350

The following table describes the items in the execution plan.

Column Description
ID The number of the execution tree obtained by Pre-Order Traversal (starting from 0).
OPERATOR The name of the operator.
NAME The name of the table or index corresponding to a table operation.
EST. ROWS The estimated number of output rows of this operator.
COST The execution cost of the operator, in microseconds.

In a table operation, the NAME field displays names (alias) of tables involved in the operation. In the case of index access, the name of the index is displayed in parentheses after the table name. For example, t1(t1_c2) indicates that index t1_c2 is used. In the case of reverse scanning, the keyword RESERVE is added after the index name, with the index name and the keyword RESERVE separated with a comma (,). For example, t1(t1_c2,Reverse).

The following table lists the common types of operators.

Type Operator
Table access TABLE SCAN, TABLE GET
Join NESTED-LOOP, BLK-NESTED-LOOP, MERGE, HASH
Sort SORT, TOP-N SORT
Aggregate MERGE GROUP-BY, HASH GROUP-BY, WINDOW FUNCTION
Distribution EXCHANGE IN/OUT REMOTE/DISTRIBUTE
Set UNION, EXCEPT, INTERSECT, MINUS
Others LIMIT, MATERIAL, SUBPLAN, EXPRESSION, COUNT

Detailed output of operators

The second part of the output of the EXPLAIN command contains the details of each operator, including the output expression, filter conditions, partition information, and unique information of each operator, such as the sort keys, join keys, and pushdown conditions.

Outputs & filters:
-------------------------------------
  0 - output([t1.c1], [t1.c2], [t2.c1], [t2.c2]), filter(nil), sort_keys([t1.c1, ASC], [t1.c2, ASC]), prefix_pos(1)
  1 - output([t1.c1], [t1.c2], [t2.c1], [t2.c2]), filter(nil),
      equal_conds([t1.c1 = t2.c2]), other_conds(nil)
  2 - output([t2.c1], [t2.c2]), filter(nil), sort_keys([t2.c2, ASC])
  3 - output([t2.c2], [t2.c1]), filter(nil),
      access([t2.c2], [t2.c1]), partitions(p0)
  4 - output([t1.c1], [t1.c2]), filter(nil),
      access([t1.c1], [t1.c2]), partitions(p0)

The key information includes:

  • output

    Each operator in the execution tree needs to output some expressions to the upstream operator for subsequent operations. This is called projection. The expressions (and common columns) that need to be projected are listed here.

  • filters

    All operators in OceanBase Database are capable of executing filters. The filters part lists the filtering operations that are performed by the operator. For table access operations, all filters (including filters before and after the table retrieval) are pushed down to the storage layer.

  • access

    Table access operations will call the storage layer interfaces to access the actual data. The access part shows the external output (projection) columns of the storage layer.

  • is_index_back and filter_before_indexback

    OceanBase Database makes a distinction between filters that can be applied before table retrieval and those that need to be applied after table retrieval. This distinction is represented by the filter_before_indexback part. If all filters can be applied before table retrieval, the is_index_back part shows "true". Otherwise, it shows "false".

  • partitions

    OceanBase Database supports sub-partitions. The optimizer filters out partitions that do not need to be accessed based on the conditions specified by the SQL statement. This step is called partition pruning. The partitions part displays the remaining partitions after partition pruning. If multiple consecutive partitions are involved, for example, from partition 0 to partition 20, the partitions are displayed in the format of "start partition number"-"end partition number", for example, partitions(p0-20).

  • range_key and range

    Theoretically, physical tables in OceanBase Database are index-organized tables (including secondary indexes) and are scanned in a specific order. This order is the primary key of the table and reflected in the range_key part. When a different condition is given by the user, the optimizer locates the final scan range and displays it in the range part, as shown in the following plan:

obclient> explain extended 
                select /*+ index(t1 t1_c2) */* from t1 where c3 = 5 and c1 = 6 order by c2, c3;
========================================
|ID|OPERATOR  |NAME     |EST. ROWS|COST|
----------------------------------------
|0 |TABLE SCAN|t1(t1_c2)|1        |1255|
========================================
Outputs & filters:
-------------------------------------
 0 - output([t1.c1(0x7f1d520a0a98)], [t1.c2(0x7f1d520a0d98)], [t1.c3(0x7f1d5209fbe0)]), filter([t1.c3(0x7f1d5209fbe0) = 5(0x7f1d5209f5d8)], [t1.c1(0x7f1d520a0a98) = 6(0x7f1d520a0490)]),
     access([t1.c3(0x7f1d5209fbe0)], [t1.c1(0x7f1d520a0a98)], [t1.c2(0x7f1d520a0d98)]), partitions(p0),
     is_index_back=true, filter_before_indexback[false,true],
     range_key([t1.c2(0x7f1d520a0d98)], [t1.c1(0x7f1d520a0a98)]), range(MIN,MIN ; MAX,MAX)always true

You can see that the index table t1_c2 is to be accessed. The primary key of the table is (c2, c1), and the scan range is the whole table.

  • sort_keys

    The sort keys for the sort operation, including the sort order.

The following table describes some common operator information.

Information Description
output The list of output expressions of the operator.
filter The filters applied by this operator.
access The projected columns of the storage layer in table access.
partitions Partition pruning information.
sort_keys The sort key for the sort operation.
prefix_pos The partially ordered offset position.
equal_conds The equivalent connection conditions applied in the connection operation.
other_conds The non-equivalent connection conditions applied in the connection operation.

Contact Us