LEFT JOIN 保留左表全部行,RIGHT JOIN 保留右表全部行,二者本质是镜像操作;实际应将需保全的表置于FROM后并用LEFT JOIN,RIGHT JOIN基本可替代且易引发理解偏差。

LEFT JOIN 和 RIGHT JOIN 的本质区别只在基准表位置
LEFT JOIN 保留左表全部行,RIGHT JOIN 保留右表全部行——它们不是功能互补,而是镜像操作。实际执行效果完全取决于你把哪个表写在 FROM 后面、哪个表写在 JOIN 后面。
比如这两条语句逻辑等价:
SELECT u.name, o.order_id FROM users u LEFT JOIN orders o ON u.id = o.user_id;
SELECT u.name, o.order_id FROM orders o RIGHT JOIN users u ON u.id = o.user_id;
但第二条可读性差,且多数人一眼看不出主表是 users。所以真实问题是:你真正想“保全”的那张表,应该放在 FROM 子句里,然后用 LEFT JOIN 接后续表。
什么时候必须用 RIGHT JOIN?基本没有
绝大多数场景下,RIGHT JOIN 完全可以用调整表顺序 + LEFT JOIN 替代。数据库引擎内部处理时,也会将 RIGHT JOIN 重写为 LEFT JOIN 再执行。
- 团队协作中,
RIGHT JOIN容易引发理解偏差——别人得倒着读才能确认主表是谁 - 嵌套多表连接时,混用
LEFT和RIGHT会让ON条件的归属变得模糊 - 部分 ORM(如 Django ORM)根本不支持
RIGHT JOIN,硬写会报错NotImplementedError
唯一可能见到 RIGHT JOIN 的地方,是维护一段历史 SQL,而原作者坚持“先写从表再写主表”。此时不建议强行改写,除非确认所有关联逻辑和 NULL 处理都无误。
LEFT JOIN 的 ON 和 WHERE 条件容易混淆
ON 是连接条件,决定哪些行能被拉进来;WHERE 是过滤条件,在连接完成后再筛结果。这个顺序不能颠倒,尤其对 LEFT JOIN。
例如想查“所有用户及其订单数,包括从未下单的用户”:
-- ✅ 正确:COUNT 能统计到 NULL 行
SELECT u.name, COUNT(o.id) FROM users u LEFT JOIN orders o ON u.id = o.user_id GROUP BY u.id;
-- ❌ 错误:WHERE o.user_id IS NOT NULL 实际上把 LEFT JOIN 变成了 INNER JOIN
SELECT u.name, COUNT(o.id) FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE o.user_id IS NOT NULL GROUP BY u.id;
关键点:
-
ON中的条件作用于右表匹配阶段,不影响左表行数 -
WHERE中对右表字段的非空判断,会直接剔除左表中本该保留的 NULL 行 - 若真要过滤右表数据(比如只看已发货订单),应把条件写进
ON:ON u.id = o.user_id AND o.status = 'shipped'
性能差异几乎可以忽略,但索引位置很关键
无论是 LEFT JOIN 还是 RIGHT JOIN,执行计划通常一样。真正影响性能的是连接字段是否有索引,以及索引是否覆盖了 ON 中的列。
常见陷阱:
- 左表小、右表大,但连接字段只在右表有索引 → 查询慢,因为引擎得遍历左表每行去右表找匹配
- 连接条件用了函数,比如
ON UPPER(a.name) = UPPER(b.name)→ 索引失效 - 多字段连接时,复合索引顺序没对齐
ON中的字段顺序 → 部分索引无法使用
别花时间纠结用 LEFT 还是 RIGHT,先检查 EXPLAIN 输出里有没有 Using join buffer 或全表扫描 —— 那才是真正的瓶颈。

















