MySQL 8.0.18起Hash Join仅支持含等值连接条件的内连接,需用EXPLAIN FORMAT=TREE或EXPLAIN ANALYZE查看;非等值条件被下推为Filter,不参与哈希构建;左/右连接不支持,BNL在8.0.20后被完全移除。

Hash Join 在 MySQL 8.0.18 初期确实不支持纯非等值连接条件(如 t1.a ),但这个说法本身已经过时——关键不在“不能”,而在于<strong>版本差异与执行逻辑的误解</strong>。
EXPLAIN FORMAT=TREE 看不到 hash join,可能只是没用对命令
- MySQL 默认的
EXPLAIN(无FORMAT)永远不显示hash join字样,只会写Using join buffer (Block Nested Loop)或类似描述,哪怕底层实际走的是 hash join。 - 必须用
EXPLAIN FORMAT=TREE或EXPLAIN ANALYZE才能看到Inner hash join、Filter等真实执行结构。 - 常见误判:看到
Extra: Using where; Using join buffer (Block Nested Loop)就以为没启用 hash join,其实那是旧格式的固定文案,从 8.0.20 起 BNL 已被完全移除,所有 join buffer 场景都由 hash join 实现。
非等值条件不是被“拒绝”,而是被“后置过滤”
MySQL 的 hash join 要求至少一对等值连接条件作为哈希构建基础(如 t1.id = t2.id),否则无法建哈希表。
-
如果 SQL 中有
ON t1.x = t2.y AND t1.z :-
t1.x = t2.y触发 hash join 构建哈希表; t1.z 被下推为 <code>Filter,在哈希匹配后逐行判断。
-
-
EXPLAIN FORMAT=TREE输出会明确分层显示:-> Inner hash join (t2.y = t1.x) -> Table scan on t2 -> Hash -> Filter: (t1.z < t2.w)
但如果写成
ON t1.x (无任何等值),8.0.18 确实会退回到不可执行状态(<code><not executable by iterator executor></not>);而 8.0.20+ 已支持纯非等值场景,原理是:先全量笛卡尔积(或扫描驱动表 × 被驱动表),再用 hash join 框架做批量比较 + 过滤,不再强依赖哈希键。
LEFT/RIGHT JOIN 在早期版本中受限,但不是因为“非等值”
- 8.0.18 仅支持
INNER JOIN使用 hash join,LEFT JOIN和RIGHT JOIN仍走传统路径(实际是 fallback 到老式 nested loop)。 - 这和“是否含非等值条件”无关,纯粹是实现覆盖范围问题。
- 8.0.20 起已支持
LEFT JOIN、RIGHT JOIN、SEMI JOIN、ANTI JOIN等多种语义的 hash join。
真正容易被忽略的一点:join_buffer_size 太小会导致 hash join 退化为磁盘临时表甚至放弃使用 —— 它不报错,但执行计划里会消失。调大该值(比如设为 4M~32M)并确认 SELECT @@join_buffer_size 生效,比纠结“为什么没走 hash”更值得优先检查。


















