EXPLAIN 语句,以及如何解读返回的执行计划,以协助您评估查询性能、定位执行瓶颈和指导调优。EXPLAIN 用于查看查询的执行计划。只读分析实例兼容 MySQL 协议,您可通过任意 MySQL 客户端连接到只读分析实例后执行 EXPLAIN。返回的计划描述了优化器为该 SQL 选择的算子组合、数据流转方式以及代价估算,可用于:语法 | 说明 | 是否实际执行 SQL |
EXPLAIN <SQL> | 查看默认(BRIEF)格式的执行计划。 | 否 |
EXPLAIN FORMAT='<格式>' <SQL> | 否 | |
EXPLAIN ANALYZE <SQL> | 实际执行 SQL,并在计划中附带每个算子的真实行数、真实代价和耗时。 | 是 |
EXPLAIN ANALYZE 会真正执行查询,对大表执行时请预估资源消耗,避免对在线业务造成影响。EXPLAIN 主要用于 SELECT 语句的执行计划查看。FORMAT 用于指定 EXPLAIN 的输出形式。常用取值如下表,建议日常使用 brief 即可,其他取值多用于诊断或工具集成场景。FORMAT 取值 | 输出形式 | 适用场景 |
brief(默认) | 表格,列:ID、OPERATOR、NAME、EST.ROWS、DETAILS | 日常查看执行计划,列宽精简,适合阅读。 |
row | 表格,列:id、operator、rows estimate、cost estimate、task type、tables visited、details | 与 brief 等价的传统输出,所有列名小写。 |
verbose | 表格,列同 row | 与 row 同结构,关注估算代价时使用。 |
tree | 树状缩进格式 | 直观查看算子层级关系。 |
detail | 表格,列同 row | 包含更完整的字段细节。 |
hint | 提示文本 | 输出当前查询可应用的 Hint 提示。 |
dot、json、traditional、true_card_cost、binary、detail_no_idsuffix 等取值,主要用于工具链集成或内部调试。日常使用建议优先使用 brief。EXPLAIN ANALYZE 会在计划之上额外输出一行阶段耗时统计,并将算子列扩展为8列。阶段耗时格式如下:TotalTime(ns):<总耗时> ParseTime(ns):<解析耗时> CompileTime(ns):<编译耗时> OptimizationTime(ns):<优化耗时> WaitTimestampTime(ns):<取时间戳耗时>
列名 | 含义 |
ID | 算子在计划中的序号。 |
OPERATOR | 算子类型。 |
NAME | 算子作用对象,例如表名、Join 类型等。 |
EST.ROWS | 优化器估算的输出行数。 |
ACT.ROWS | 实际输出行数。 |
ACT.OUTPUTSIZE | 实际输出字节数。 |
EST.COST | 优化器估算的代价。 |
ACT.COST | 实际代价(含执行耗时占比)。 |
EST.ROWS 与 ACT.ROWS,可快速识别统计信息偏差或选择率估算误差导致的执行计划问题。列名 | 含义 |
ID | 算子在计划中的序号,按从根到叶子的深度优先顺序编号。 |
OPERATOR | 算子类型,例如 HASH JOIN、TABLE FULL SCAN、EXCHANGE SENDER 等。 |
NAME | 算子作用对象,例如表名( TABLE FULL SCAN 显示表名)、Join 类型简称等。 |
EST.ROWS | 优化器基于统计信息估算的输出行数。 |
DETAILS |
HASH JOIN 算子的两个子节点上,ID 列会附加后缀,用于标识该子节点在 Hash Join 中扮演的角色。后缀 | 含义 |
(B) | Build 端。Hash Join 会先扫描 Build 端的数据并构建哈希表。 |
(P) | Probe 端。Hash Join 用 Probe 端的每一行去探测哈希表得到匹配结果。 |
HASH_JOIN_BUILD 和 HASH_JOIN_PROBE 这两个 Hint,详见 Optimizer Hint 章节。类别 | 算子 | 说明 |
扫描 | TABLE FULL SCAN | 全表扫描列存数据。Libr 中最常见的扫描算子。 |
扫描 | COLUMN READ | 列存读取算子,按需读取参与计算的列。 |
扫描 | REMOTE READER* | 远程读算子,当 SQL 涉及 TDSQL 行存数据时出现,将子计划下推到 TDSQL 行存执行后回传结果。 |
扫描 | INDEX FULL SCAN* | 索引全扫描,一般出现在 REMOTE READER 子树中。 |
扫描 | INDEX RANGE SCAN* | 索引范围扫描,一般出现在 REMOTE READER 子树中。 |
Join | HASH JOIN | 哈希连接。按 Join 类型可显示为 HASH JOIN、HASH OUTER JOIN、HASH RIGHT OUTER JOIN、HASH SEMI JOIN、HASH NA-SEMI JOIN(NA 表示 Null-Aware)。 |
Join | MERGE JOIN* | 归并连接,要求两侧输入按 Join 键有序。 |
聚合 | HASH GROUP BY | 基于哈希表的分组聚合。 |
聚合 | MERGE GROUP BY* | 基于有序输入的流式聚合。 |
排序与限流 | SORT | 排序算子。 |
排序与限流 | TOPN | 取前 N 条算子,等价于带 LIMIT 的排序,一般比 SORT + LIMIT 更高效。 |
排序与限流 | LIMIT | 限制返回行数。 |
投影与过滤 | PROJECTION | 投影算子,输出表达式列表。 |
投影与过滤 | FILTER | 过滤算子,对应 SQL 中的 WHERE、HAVING 等条件。 |
集合与窗口 | UNION | 合并多路输入。 |
集合与窗口 | WINDOW FUNCTION | 窗口函数算子。 |
分布式交换 | EXCHANGE SENDER | MPP 数据交换发送端,向上游节点发送数据。 |
分布式交换 | EXCHANGE RECEIVER | MPP 数据交换接收端,从下游节点接收数据。 |
分布式交换 | LOCAL SHUFFLE* | 节点内多线程数据重分发。 |
物化与 CTE | MATERIAL* | 中间结果物化。 |
物化与 CTE | RECURSIVE UNION* | 递归 CTE。 |
物化与 CTE | CTE MATERIAL* | CTE 物化结果。 |
物化与 CTE | CTE FULL SCAN* | 读取已物化的 CTE 结果。 |
DETAILS 列中可能输出的字段。具体出现哪些字段取决于该算子的实际配置。字段 | 含义 |
STORAGE | 存储引擎类型。取值为 LIBRASTORE(列存分析引擎)或 TDSQL(TDSQL 行存)。 |
TABLE NAME | 被扫描的表名。 |
TABLE ALIAS | SQL 中为该表指定的别名(如有)。 |
ACCESS COLUMN | 实际读取的列名列表。Libra 是列存,仅读取需要参与计算的列。 |
BLOCK OFFSET | 列存数据块的偏移信息,由系统自动管理,用户无需关注。 |
Partitions | 实际命中的分区列表(如有)。 |
KEEP ORDER | 是否需要保持有序输出。 |
DESC | 是否倒序扫描。 |
COMPLETE PIPELINE | 是否完整流水线扫描。 |
PROBE RUNTIME FILTERS | Probe 端 Runtime Filter 列表。Runtime Filter 是 Hash Join 在 Build 端构建的过滤器,下推到 Probe 端的扫描或上层算子中提前过滤数据,以减少后续计算量。 |
字段 | 含义 |
EQUAL | 等值连接条件列表,例如 [eq(t1.a, t2.a)]。 |
OTHER COND | 其他连接/过滤条件。 |
BUILD RUNTIME FILTERS | 在 Build 端构建的 Runtime Filter 列表,会下推到 Probe 端的扫描或过滤算子。 |
PROBE RUNTIME FILTERS | 来自上游的 Probe 端 Runtime Filter 列表(如有)。 |
JOIN TYPE 字段,连接类型直接体现在算子名称上(如 HASH JOIN、HASH OUTER JOIN、HASH SEMI JOIN、HASH NA-SEMI JOIN);NON EQUAL/JOIN TYPE 这两个字段仅在 Apply(关联子查询)算子的 DETAILS 中输出。字段 | 含义 |
EXCHANGE TYPE | 数据交换类型。取值与含义参见下表。 |
HASH COLS | 当 EXCHANGE TYPE 为 HASH 时,用于哈希分发的列列表。 |
PARTITION DISTRIBUTION | 当 EXCHANGE TYPE 为 HASH (BY PARTITION) 时,按分区分发的分布信息。 |
EXCHANGE TYPE 的取值如下。取值 | 完整名称 | 含义 |
PASS | PassThrough | 直接透传,不重分发数据。 |
BCJ | Broadcast | 广播模式,将数据复制到所有上游节点,常用于小表 Broadcast Join。 |
HASH | HashPartition | 按指定列哈希后分发,常用于大表 Hash Join 的数据重分布。 |
HASH (BY PARTITION) | Partition Key(HASH) | 按分区键的哈希值分发,使同一分区的数据聚集到同一节点。 |
KEEP ORDER 字段。字段 | 含义 |
group by | 分组列列表。 |
funcs | 聚合函数列表,例如 count(*)、sum(t.a)。 |
字段 | 含义 |
排序键列表 | 按排序优先级列出,每项可附带 asc 或 desc。 |
OFFSET | TOPN 的偏移量。 |
COUNT | TOPN 取的记录数。 |
字段 | 含义 |
offset | 跳过的行数。 |
count | 返回的行数。 |
[gt(t.a, 10)]。WINDOW FUNC DESCS(窗口函数描述)、PARTITION BY 列、ORDER BY 列、窗口框架(Frame)定义等。SELECT 关键字后面的 /*+ ... */ 注释块中。Hint | 作用 |
HASH_JOIN(t1, t2) | 强制 t1 与 t2 使用 Hash Join。 |
HASH_JOIN_BUILD(t) | 指定 t 为 Hash Join 的 Build 端。 |
HASH_JOIN_PROBE(t) | 指定 t 为 Hash Join 的 Probe 端。 |
MERGE_JOIN(t1, t2) | 强制使用 Merge Join。 |
INL_JOIN(t1, t2) | 强制使用 Index Nested Loop Join。 |
INL_HASH_JOIN(t1, t2) | 强制使用 Index Hash Join。 |
INL_MERGE_JOIN(t1, t2) | 强制使用 Index Merge Join。 |
USE_HASH(t1, t2) | 提示优化器优先选择 Hash Join。 |
NO_USE_HASH(t1, t2) | 提示优化器不要为 t1 和 t2 选择 Hash Join。 |
PX_JOIN_FILTER(id [, type]) | 强制为指定 Join 生成 Runtime Filter(即 Build 端构建的预过滤器)。 |
NO_PX_JOIN_FILTER(id [, type]) | 禁止为指定 Join 生成 Runtime Filter。 |
SEMI_JOIN_REWRITE() | 启用 Semi Join 改写优化。 |
INL_JOIN、INL_HASH_JOIN、INL_MERGE_JOIN、MERGE_JOIN 等)在列存执行路径下可能不会被采纳,请以 EXPLAIN 的实际输出为准。t2 作为 Hash Join 的 Probe 端:SELECT /*+ HASH_JOIN_PROBE(t2) */ *FROM t1 JOIN t2 ON t1.id = t2.id;
EXPLAIN 后,可在计划的 ID 列看到 t2 子树带有 (P) 后缀,t1 子树带有 (B) 后缀,从而验证 Hint 已生效。EXPLAINSELECT t1.name, COUNT(*)FROM t1 JOIN t2 ON t1.id = t2.idWHERE t2.region = 'cn'GROUP BY t1.nameORDER BY COUNT(*) DESCLIMIT 10;
TOPN:等价于 ORDER BY ... LIMIT 10,在排序的同时只保留前 10 行。PROJECTION:将分组结果投影为最终输出列。HASH GROUP BY:按 t1.name 分组并执行 COUNT(*)。EXCHANGE RECEIVER / EXCHANGE SENDER:按 t1.name 哈希重分布,便于分组聚合并行。HASH JOIN:按 t1.id = t2.id 进行连接,子节点 ID 列分别带有 (B) 和 (P) 后缀。TABLE FULL SCAN:分别扫描 t1 和 t2,STORAGE 列显示 LIBRASTORE,ACCESS COLUMN 仅包含真正参与计算的列;t2 上可能附加 PROBE RUNTIME FILTERS 字段,表示 Hash Join 在 Build 端构建的 Runtime Filter 已下推到该 Probe 端进行预过滤。EXPLAIN ANALYZE 重新执行该 SQL,可对比 EST.ROWS 与 ACT.ROWS 是否接近,从而判断统计信息是否准确。如有较大偏差,可执行 ANALYZE TABLE 收集最新统计信息。文档反馈