mysql中LEFT JOIN与RIGHT JOIN的差异与选择

LEFT JOIN 以左表为主表,RIGHT JOIN 以右表为主表,本质是主表选择不同;二者逻辑对称,可相互转换;实际开发中因可读性差、反直觉而极少使用。

mysql中left join与right join的差异与选择

LEFT JOIN 和 RIGHT JOIN 的本质区别在哪?

本质就一条:谁是主表(保留全部记录的表),谁是从表(只填匹配项,不匹配就 NULL)。LEFT JOINFROM 后第一个表(左表)为主表RIGHT JOIN 则以 JOIN 后那个表(右表)为主表。其他逻辑完全对称——不是“功能不同”,而是“主次关系翻转”。

  • SELECT * FROM A LEFT JOIN B ON A.id = B.a_id → A 全出,B 匹配不上就 NULL
  • SELECT * FROM A RIGHT JOIN B ON A.id = B.a_id → B 全出,A 匹配不上就 NULL
  • 二者结果集可以完全等价:把表顺序调换 + 改用 LEFT JOIN 就能替代 RIGHT JOIN(例如 SELECT * FROM B LEFT JOIN A ON A.id = B.a_id

实际开发中为什么几乎不用 RIGHT JOIN?

不是它不能用,而是它容易引发阅读和维护陷阱。人脑读 SQL 习惯从左到右,FROM A RIGHT JOIN B 看着像“先查 A 再右连 B”,但实际语义却是“以 B 为主”,反直觉。团队协作时,别人扫一眼容易误判主表意图。

  • 绝大多数 LEFT JOIN 场景都能通过调整表顺序重写为 LEFT JOIN,更符合思维惯性
  • MySQL 执行器对 LEFT JOINRIGHT JOIN 的优化路径一致,性能无差异
  • 部分 ORM(如 Django ORM、MyBatis Plus)默认只生成 LEFT JOIN,不支持显式 RIGHT JOIN 语法
  • 代码审查时,遇到 RIGHT JOIN 往往会被要求重构 —— 不是错,是“不够清晰”

什么时候必须用 RIGHT JOIN?

几乎没有“必须”。但极少数场景下,若强行用 LEFT JOIN 会导致嵌套过深或别名混乱,可权衡使用。例如:已有复杂子查询作为左表,又想以右侧基础维表(如 dim_region)为基准补全所有区域信息,此时写 (subquery) RIGHT JOIN dim_region 可避免把子查询再包一层 FROM

SELECT u.name, r.region_name
FROM (
  SELECT user_id, name FROM users WHERE status = 1
) u
RIGHT JOIN dim_region r ON u.region_id = r.id;

但更推荐写法仍是把维表放前面:

人民网AIGC-X

人民网AIGC-X

国内科研机构联合推出的AI生成内容检测工具

下载

SELECT u.name, r.region_name
FROM dim_region r
LEFT JOIN users u ON u.region_id = r.id AND u.status = 1;

LEFT JOIN 中 ON 和 WHERE 的坑你踩过吗?

这是比 LEFT/RIGHT 选择更常翻车的地方:ON 是连接时过滤右表;WHERE 是连接后过滤整行。一旦在 LEFT JOIN 后加了 WHERE 右表字段 IS NOT NULL,就事实退化成 INNER JOIN。

  • 错误写法(本想查所有部门 + 员工数,却漏掉无人部门):
    SELECT d.name, COUNT(e.id) FROM dept d LEFT JOIN emp e ON d.id = e.dept_id WHERE e.id IS NOT NULL GROUP BY d.name;
  • 正确写法(保留 NULL 部门):
    SELECT d.name, COUNT(e.id) FROM dept d LEFT JOIN emp e ON d.id = e.dept_id GROUP BY d.name;
  • 想筛“有员工的部门”?直接用 INNER JOIN,语义更干净

LEFT JOIN 的真正价值,在于“保左表完整性”;一旦 WHERE 拿右表字段做非 NULL 判断,这个保证就失效了——这点比纠结 LEFT 还是 RIGHT 重要得多。

https://www.php.cn/faq/1977071.html

发表回复

Your email address will not be published. Required fields are marked *