PingKai Logo下载

EXPLAIN

EXPLAIN 语句用于展示查询的执行计划,但不会实际执行该查询。它与会实际执行查询的 EXPLAIN ANALYZE 语句互为补充。如果 EXPLAIN 的输出结果与预期不符,建议对查询中涉及的每个表执行 ANALYZE TABLE,以确保表统计信息是最新的。

DESC 和 DESCRIBE 语句是 EXPLAIN 语句的别名。EXPLAIN <tableName> 的另一种用法已在 SHOW [FULL] COLUMNS FROM 中记录。

TiDB 支持 EXPLAIN [options] FOR CONNECTION connection_id 语句。但该语句与 MySQL 中的 EXPLAIN FOR 语句不同。详情请参见 EXPLAIN FOR CONNECTION。

语法

ExplainSym
EXPLAIN DESCRIBE DESC
ExplainStmt
ExplainSym TableName ColumnName ANALYZE ExplainableStmt FOR CONNECTION NUM FORMAT = stringLit ExplainFormatType FOR CONNECTION NUM ExplainableStmt
ExplainableStmt
SelectStmt DeleteFromStmt UpdateStmt InsertIntoStmt ReplaceIntoStmt UnionStmt

EXPLAIN 输出格式

目前,TiDB 中的 EXPLAIN 输出包含 5 列:id、estRows、task、access object、operator info。执行计划中的每个算子都由这些属性描述,EXPLAIN 输出的每一行描述一个算子。各属性说明如下:

属性名描述
id算子 ID,是整个执行计划中该算子的唯一标识。在 TiDB 2.1 中,ID 的格式用于展示算子的树形结构。数据流从子节点流向父节点。每个算子有且仅有一个父节点。
estRows算子预计输出的行数。该数值根据统计信息和算子逻辑进行估算。estRows 在 TiDB 4.0 早期版本中称为 count。
task算子所属的任务类型。目前,执行计划分为两类任务:root 任务(在 tidb-server 上执行)和 cop 任务(在 TiKV 或 TiFlash 上并行执行)。执行计划在任务层级的拓扑结构为一个 root 任务后接多个 cop 任务。root 任务以 cop 任务的输出为输入。cop 任务指 TiDB 下推到 TiKV 或 TiFlash 的任务。每个 cop 任务分布在 TiKV 集群或 TiFlash 集群中,由多个进程执行。
access object算子访问的数据项信息。信息包括 table、partition 和 index(如有)。只有直接访问数据的算子才有该信息。
operator info算子的其他信息。每个算子的 operator info 不同,可参考下方示例。

示例

EXPLAIN SELECT 1;
+-------------------+---------+------+---------------+---------------+
| id                | estRows | task | access object | operator info |
+-------------------+---------+------+---------------+---------------+
| Projection_3      | 1.00    | root |               | 1->Column#1   |
| └─TableDual_4     | 1.00    | root |               | rows:1        |
+-------------------+---------+------+---------------+---------------+
2 rows in set (0.00 sec)
CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, c1 INT NOT NULL);
Query OK, 0 rows affected (0.10 sec)
INSERT INTO t1 (c1) VALUES (1), (2), (3);
Query OK, 3 rows affected (0.02 sec)
Records: 3  Duplicates: 0  Warnings: 0
EXPLAIN SELECT * FROM t1 WHERE id = 1;
+-------------+---------+------+---------------+---------------+
| id          | estRows | task | access object | operator info |
+-------------+---------+------+---------------+---------------+
| Point_Get_1 | 1.00    | root | table:t1      | handle:1      |
+-------------+---------+------+---------------+---------------+
1 row in set (0.00 sec)
DESC SELECT * FROM t1 WHERE id = 1;
+-------------+---------+------+---------------+---------------+
| id          | estRows | task | access object | operator info |
+-------------+---------+------+---------------+---------------+
| Point_Get_1 | 1.00    | root | table:t1      | handle:1      |
+-------------+---------+------+---------------+---------------+
1 row in set (0.00 sec)
DESCRIBE SELECT * FROM t1 WHERE id = 1;
+-------------+---------+------+---------------+---------------+
| id          | estRows | task | access object | operator info |
+-------------+---------+------+---------------+---------------+
| Point_Get_1 | 1.00    | root | table:t1      | handle:1      |
+-------------+---------+------+---------------+---------------+
1 row in set (0.00 sec)
EXPLAIN INSERT INTO t1 (c1) VALUES (4);
+----------+---------+------+---------------+---------------+
| id       | estRows | task | access object | operator info |
+----------+---------+------+---------------+---------------+
| Insert_1 | N/A     | root |               | N/A           |
+----------+---------+------+---------------+---------------+
1 row in set (0.00 sec)
EXPLAIN UPDATE t1 SET c1=5 WHERE c1=3;
+---------------------------+---------+-----------+---------------+--------------------------------+
| id                        | estRows | task      | access object | operator info                  |
+---------------------------+---------+-----------+---------------+--------------------------------+
| Update_4                  | N/A     | root      |               | N/A                            |
| └─TableReader_8           | 0.00    | root      |               | data:Selection_7               |
|   └─Selection_7           | 0.00    | cop[tikv] |               | eq(test.t1.c1, 3)              |
|     └─TableFullScan_6     | 3.00    | cop[tikv] | table:t1      | keep order:false, stats:pseudo |
+---------------------------+---------+-----------+---------------+--------------------------------+
4 rows in set (0.00 sec)
EXPLAIN DELETE FROM t1 WHERE c1=3;
+---------------------------+---------+-----------+---------------+--------------------------------+
| id                        | estRows | task      | access object | operator info                  |
+---------------------------+---------+-----------+---------------+--------------------------------+
| Delete_4                  | N/A     | root      |               | N/A                            |
| └─TableReader_8           | 0.00    | root      |               | data:Selection_7               |
|   └─Selection_7           | 0.00    | cop[tikv] |               | eq(test.t1.c1, 3)              |
|     └─TableFullScan_6     | 3.00    | cop[tikv] | table:t1      | keep order:false, stats:pseudo |
+---------------------------+---------+-----------+---------------+--------------------------------+
4 rows in set (0.01 sec)

你可以通过 FORMAT = xxx 语法指定 EXPLAIN 输出的格式。目前,TiDB 支持以下几种格式:

FORMAT描述
未指定如果未指定格式,EXPLAIN 使用默认的 row 格式。
brief与未指定 FORMAT 时相比,EXPLAIN 语句输出中的算子 ID 更为简化。
dotEXPLAIN 语句输出 DOT 执行计划,可通过 dot 程序(在 graphviz 包中)生成 PNG 文件。
rowEXPLAIN 语句以表格形式输出结果。更多信息参见 理解查询执行计划。
tidb_jsonEXPLAIN 语句以 JSON 格式输出执行计划,并将算子信息存储在 JSON 数组中。
verboseEXPLAIN 语句以 row 格式输出结果,并在结果中增加 estCost 列,显示查询的估算成本。关于如何使用该格式,参见 SQL 执行计划管理。
plan_cacheEXPLAIN 语句以 row 格式输出结果,并以警告形式输出 Plan Cache 信息。
cost_traceEXPLAIN 语句以扩展的 row 格式输出结果,增加两列:estCost(估算成本)和 costFormula(成本公式)。

以下为 EXPLAIN 中 FORMAT 为 "brief" 时的示例:

EXPLAIN FORMAT = "brief" DELETE FROM t1 WHERE c1 = 3;
+-------------------------+---------+-----------+---------------+--------------------------------+
| id                      | estRows | task      | access object | operator info                  |
+-------------------------+---------+-----------+---------------+--------------------------------+
| Delete                  | N/A     | root      |               | N/A                            |
| └─TableReader           | 0.00    | root      |               | data:Selection                 |
|   └─Selection           | 0.00    | cop[tikv] |               | eq(test.t1.c1, 3)              |
|     └─TableFullScan     | 3.00    | cop[tikv] | table:t1      | keep order:false, stats:pseudo |
+-------------------------+---------+-----------+---------------+--------------------------------+
4 rows in set (0.001 sec)

MySQL 兼容性

  • TiDB 中 EXPLAIN 的格式及可能的执行计划与 MySQL 有较大差异。
  • TiDB 不支持 FORMAT=JSON 或 FORMAT=TREE 选项。
  • TiDB 中的 FORMAT=tidb_json 是默认 EXPLAIN 结果的 JSON 格式输出,其格式和字段与 MySQL 的 FORMAT=JSON 输出不同。

EXPLAIN FOR CONNECTION

EXPLAIN FOR CONNECTION 用于获取某个连接当前正在执行的 SQL 查询或上一次执行的 SQL 查询的执行计划。输出格式与 EXPLAIN 相同。但 TiDB 中 EXPLAIN FOR CONNECTION 的实现与 MySQL 不同。两者的区别(除输出格式外)如下:

  • 如果连接处于 sleeping 状态,MySQL 返回空结果,而 TiDB 返回上一次执行的查询计划。
  • 如果你尝试获取当前会话的执行计划,MySQL 会返回错误,而 TiDB 会正常返回结果。
  • MySQL 要求登录用户与被查询连接的用户相同,或登录用户拥有 PROCESS 权限;而 TiDB 要求登录用户与被查询连接的用户相同,或登录用户拥有 SUPER 权限。

另请参阅