🎯 深入理解:JOIN 中 ON vs WHERE 条件差异

很多人在写 SQL 时,会混用 ONWHERE 限制条件。但这并不是无关紧要的"风格"问题,尤其在 OUTER JOIN(如 LEFT JOIN)中,放错地方逻辑就彻底变了


1️⃣ 基础:ON 做"配对",WHERE 做"筛选"

  • ON 子句:定义两个表之间"如何配对"的逻辑。
  • WHERE 子句:在配对完成后对结果进行过滤,决定哪些行最终返回。

正如社区大佬所说:

"The ON clause defines the relationship between the tables. The WHERE clause describes which rows you are interested in." stackoverflow.com+14stackoverflow.com+14geeksforgeeks.org+14


2️⃣ INNER JOIN:语义一致,差距仅在"表达方式"

对于 INNER JOIN(内连接),无论你把条件放在 ON 还是 WHERE,结果集最终都一样------这是数学上的布尔逻辑统一:

css 复制代码
-- a) 条件放在 ON
SELECT *
FROM A
JOIN B ON A.id = B.id AND B.status = 'active';

-- b) 条件放在 WHERE
SELECT *
FROM A
JOIN B ON A.id = B.id
WHERE B.status = 'active';

Percona 专家总结:

"No, there's no difference. ... MySQL will have the same execution plan." reddit.com+3percona.com+3bennadel.com+3


3️⃣ OUTER JOIN(如 LEFT JOIN):逻辑大崩盘!

这里是关键!不当使用就可能把含 NULL 的行"干掉",从 LHS 表漏掉记录。

👇 场景 A:想保留左表所有行,并只在右表满足条件时才关联

ini 复制代码
SELECT u.name, h.info
FROM users u
LEFT JOIN houses h
  ON u.id = h.owner_id
   AND h.status = 'rented';
  • 执行流程

    1. 先取 users 表整表扫描;
    2. 每行尝试在 houses 表中配对 owner_id + status;
    3. 如果不满足 status = 'rented',仍保留 users 行,但 houses 字段为 NULL
      ✅ 保证"users 全保、houses 有条件过滤"

来自 Kateryna 的清晰说明:

"when the filter is on ON clause, ... dept table is filtered before being left joined ... NULL entries ..." blog.jooq.org+2en.wikipedia.org+2mode.com+2dba.stackexchange.com+10pluralsight.com+10geeksforgeeks.org+10blog.jooq.org+2learnsql.com+2dba.stackexchange.com+2

🔥 场景 B:把条件挪到 WHERE------逻辑彻底变了!

ini 复制代码
SELECT u.name, h.info
FROM users u
LEFT JOIN houses h
  ON u.id = h.owner_id
WHERE h.status = 'rented';
  • 这时候 SQL 语义变成:

    1. 先完全关联;
    2. 然后丢弃 h.status != 'rented' 的行;
    3. 最可怕的是------那些 houses=NULL 的行,也会被一起剔除。
      结果就是 Left Join 切成 Inner Join

正如 dev.to 上所述:

"this filter ... filter rows after the join ... effectively an inner join in disguise" blog.jooq.orgdev.to+1dev.to+1dba.stackexchange.com+2pluralsight.com+2geeksforgeeks.org+2


4️⃣ 性能差异?

  • INNER JOIN 条件放哪不会影响执行计划;
  • LEFT JOIN 时,把限制尽量放 ON 中能让 SQL 引擎少输出 NULL 行再过滤,在大数据场景下性能更优 w3schools.com+14percona.com+14blog.jooq.org+14
  • 但很多优化器智能到把顺序重组,主流 MySQL/Percona 通常无明显差异 percona.com

5️⃣ 心智模型 & 记忆锚

JOIN 类型 ON 里加条件 WHERE 里加条件
INNER JOIN ✅ 同效果,推荐在 ON 放条件,提高可读性 ✅ Late filter,清晰逐位"配对"后再筛选
LEFT JOIN ✅ 想保留左表全量结果时,请把条件放 ON ❌ 条件放 WHERE,等于转成 INNER JOIN,漏掉 NULL

口诀

  • JOIN 用 ON,配对优先
  • 条件用 WHERE,事后筛选
  • 想要 Outer Join 保数据?条件要写在 ON!

6️⃣ 实战建议

  • INNER JOIN:条件语义清晰,放 ON 更能"一眼明白"。

  • LEFT JOIN

    • 保左删右ON u.id = h.uid AND h.flag='ok'
    • 啥都保但最终筛条件 :使用 WHERE ,注意 NULL 行可能被删。

✨ 总结:别再"套用模板",Think before you write

  • ON = 连接逻辑,决定两表如何组合。
  • WHERE = 全表过滤,决定最后哪些行被展示。
  • 错用会让语句"看着左连接,结果像内连接",逻辑漏洞埋在细节里。
相关推荐
程序员岳焱34 分钟前
Java 与 MySQL 性能优化:Java 实现百万数据分批次插入的最佳实践
后端·mysql·性能优化
FrankYoou38 分钟前
Jenkins 与 GitLab CI/CD 的核心对比
java·docker
麦兜*1 小时前
Spring Boot启动优化7板斧(延迟初始化、组件扫描精准打击、JVM参数调优):砍掉70%启动时间的魔鬼实践
java·jvm·spring boot·后端·spring·spring cloud·系统架构
KK溜了溜了1 小时前
JAVA-springboot 整合Redis
java·spring boot·redis
大只鹅1 小时前
解决 Spring Boot 对 Elasticsearch 字段没有小驼峰映射的问题
spring boot·后端·elasticsearch
ai小鬼头1 小时前
AIStarter如何快速部署Stable Diffusion?**新手也能轻松上手的AI绘图
前端·后端·github
天河归来2 小时前
使用idea创建springboot单体项目
java·spring boot·intellij-idea
weixin_478689762 小时前
十大排序算法汇总
java·算法·排序算法
码荼2 小时前
学习开发之hashmap
java·python·学习·哈希算法·个人开发·小白学开发·不花钱不花时间crud
梦在深巷、2 小时前
MySQL/MariaDB数据库主从复制之基于二进制日志的方式
linux·数据库·mysql·mariadb