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

很多人在写 SQL 时,会混用 ON 和 WHERE 限制条件。但这并不是无关紧要的"风格"问题,尤其在 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 = 全表过滤,决定最后哪些行被展示。
  • 错用会让语句"看着左连接,结果像内连接",逻辑漏洞埋在细节里。
相关推荐
哦虎!2 小时前
【JavaEE】网络初识
java
for_ever_love__2 小时前
MySQL ORDER BY 排序优化:从 Using filesort 到索引有序扫描(含双路 / 单路排序原理)
java·mysql·优化·存储·by·order·filesort
大鸡腿同学3 小时前
手心向上,手心向下
后端
我是人✓3 小时前
Java文件上传三方式对比:从传统到SpringBoot
java·开发语言
欣栀♡3 小时前
JVM 频繁 Full GC 先看日志括号里的 cause,jstat 的 FGC 在 JDK 8 上会骗人
java·jvm
CCblandy3 小时前
令牌桶在 0.9 倍负载超发 19%、固定窗口边界放行 20 个:四种限流算法同构实测
后端·python·算法·性能优化·架构
IT研究室3 小时前
最新计算机毕业设计选题推荐-基于spring boot的葡萄酒文化宣传网站-网站-文档指导-Java-springboot
java·spring boot·课程设计
慧都小项3 小时前
MyEclipse 中创建和测试 JAX-RS REST 接口:从项目配置到 REST Explorer
java·restful·myeclipse·jax-rs
Wang's Blog3 小时前
Java 项目实战: 交友项目 - 入门案例:编写 Dubbo 服务提供者
java·dubbo·交友
秋饼4 小时前
Spring AI 2.0 结构化输出企业级实战:从 BeanOutputConverter 源码到生产级解析容错
java·ai·技术分享·后端开发