MySQL将RIGHT JOIN重写为等价LEFT JOIN,执行逻辑完全一致;真正影响性能的是驱动表选择而非连接方向,且WHERE中对被驱动表字段的非空限制会使外连接退化为内连接。

底层执行逻辑完全相同,MySQL 查询优化器对 LEFT JOIN 和 RIGHT JOIN 的处理路径一致,不存在性能或计划生成层面的差异。
MySQL 优化器不区分 LEFT/RIGHT 的语义方向
优化器在解析阶段就会将 RIGHT JOIN 重写为等价的 LEFT JOIN 形式——它直接交换两表顺序并翻转连接类型。例如:
SELECT * FROM orders RIGHT JOIN customers ON orders.customer_id = customers.id;
会被优化器内部转成:
SELECT * FROM customers LEFT JOIN orders ON orders.customer_id = customers.id;
这意味着:
- 执行计划(EXPLAIN 输出)中不会出现
RIGHT JOIN节点,全被归一化为LEFT JOIN - 索引选择、驱动表判定、条件推送(condition pushdown)等优化行为完全一致
- 即使你手写
RIGHT JOIN,SHOW WARNINGS通常能看到重写后的语句
真正影响执行效率的是“谁是驱动表”,不是 LEFT/RIGHT 关键字
MySQL 的 Nested-Loop Join 实际以“左表为驱动表”执行(无论语法写的是 LEFT 还是 RIGHT),但这个“左”指的是重写后语句里的左表。所以关键其实是物理表顺序:
- 写
A LEFT JOIN B→ 优化器保留 A 为驱动表 - 写
A RIGHT JOIN B→ 优化器重写为B LEFT JOIN A→ 实际驱动表变成 B
也就是说,RIGHT JOIN 的“右表”在执行时反而成了事实上的驱动表。如果你没意识到这点,可能误判索引该建在哪边。
WHERE 条件和 NULL 检查会实质性改变连接行为
很多人以为加个 WHERE b.col IS NOT NULL 只是过滤,其实它会让 LEFT JOIN 退化为 INNER JOIN 语义(优化器可能改用内连计划)。同理,对右表字段的非空限制也会让 RIGHT JOIN 失去外连接特性。
- 写
A LEFT JOIN B ON ... WHERE B.id IS NOT NULL→ 实际等效于A INNER JOIN B - 这种写法容易掩盖业务意图,也干扰优化器对 NULL 安全性的判断
- 若真需要保留右表全部记录,就别在 WHERE 里碰右表字段;该放 ON 的条件别挪到 WHERE
真正难处理的从来不是 LEFT 和 RIGHT 的语法区别,而是驱动表选择、索引覆盖、以及 ON/WHERE 边界模糊带来的语义漂移——这些地方一错,执行计划就彻底跑偏。


















