EXPLAIN FORMAT=TREE是唯一能直观显示Hash Join构建表、探测表及连接键的命令,其树状结构中“Inner hash join (t2.c1 = t1.c1)”明确标识探测表字段在左、构建表字段在右,带Hash标签的子节点为构建表扫描,另一支为探测表扫描;EXPLAIN ANALYZE则补充实际扫描行数、build/probe耗时及disk overflow标记,可验证内存是否充足、驱动表选择是否合理。
EXPLAIN FORMAT=TREE 是唯一能直观看到 Hash Join 匹配过程的命令,其他格式(如 EXPLAIN 默认或 EXPLAIN FORMAT=TRADITIONAL)只会显示 Using join buffer (hash join) 这类模糊提示,无法反映构建表、探测表、哈希键等关键结构。
EXPLAIN FORMAT=TREE 输出里的 Hash Join 节点输出是嵌套树状结构,每层缩进代表执行层级。Hash Join 节点本身会明确写出 Inner hash join 或 Left hash join,并标注连接键,例如:Inner hash join (t2.c1 = t1.c1)。
t2.c1)是探测表(被驱动表)的连接列t1.c1)是构建表(驱动表)的连接列Hash 标签的那一支,就是构建阶段扫描的表(如 Table scan on t1)Hash 的,就是探测阶段扫描的表(如 Table scan on t2)hash join 嵌套(比如三表 JOIN),说明 MySQL 拆成了多个两表 Hash Join 步骤,从右向左或按代价估算顺序执行EXPLAIN ANALYZE 能补全哪些关键信息?EXPLAIN ANALYZE 会在实际执行 SQL 后返回运行时统计,比 FORMAT=TREE 多出三类关键数据:
rows 字段),可验证优化器是否真选了小表做构建表build time)和探测耗时(probe time),差距大说明内存不足触发了磁盘溢出disk overflow —— 若出现该字样,说明构建表超出 join_buffer_size,已分块写入磁盘,性能必然下降常见原因不是语法错,而是优化器“绕过”了它:
OR、LIKE、函数表达式(如 UPPER(t1.name) = t2.name),哪怕只有一处,整个 ON 子句就不再满足纯等值条件WHERE t1.id = ? 有主键索引),优化器倾向用 Index Nested-Loop Join,即使连接列本身无索引ANALYZE TABLE 没执行过,导致优化器误判构建表大小,选错驱动方SET optimizer_switch='hash_join=off' 关闭,但 8.0.20+ 该开关已失效,无需检查最可靠的方式不是猜配置,而是控制输入结构:
SELECT * FROM (SELECT * FROM t1 WHERE ... ) AS a JOIN (SELECT * FROM t2 WHERE ... ) AS b ON a.c1 = b.c1
)ANALYZE TABLE t1, t2 更新统计信息EXPLAIN FORMAT=TREE 看树形结构,再用 EXPLAIN ANALYZE 看真实耗时与溢出标记真正容易被忽略的是:Hash Join 的性能优势高度依赖构建表能否全量驻留内存。一旦触发磁盘溢出,I/O 开销可能反超 Nested-Loop —— 所以 join_buffer_size 不是越大越好,而是要略大于预估的构建表字节大小(注意是字节数,不是行数)。