on定义关联规则,where筛选最终结果;left join中右表条件须放on避免丢数据,放where则退化为inner join。

ON 和 WHERE 不是可互换的条件位置,放错地方会直接改变结果集,尤其在外连接中可能丢数据。
LEFT JOIN 里把过滤条件写在 WHERE 就会丢左表记录
LEFT JOIN 的本意是“保留左表所有行”,但一旦在 WHERE 中引用右表字段(比如 WHERE o.status = 'paid'),数据库会在连接完成后才过滤——此时右表为 NULL 的行(即左表没匹配上的)会被整个剔除。
- ✅ 正确:条件写在
ON里 →LEFT JOIN orders o ON u.id = o.user_id AND o.status = 'paid',左表用户全在,没支付订单的o.*字段为NULL - ❌ 错误:条件写在
WHERE里 →LEFT JOIN orders o ON u.id = o.user_id WHERE o.status = 'paid',结果等价于INNER JOIN,没支付订单的用户直接消失 - 注意:只要
WHERE中出现右表字段(哪怕加了IS NULL判断),就破坏了 LEFT JOIN 的语义保证
INNER JOIN 中 ON 和 WHERE 看似等效,但执行路径不同
结果一样不等于过程一样。优化器对 ON 条件能更早剪枝,影响连接算法选择和索引使用;WHERE 是连接完再扫一遍结果,多一次 filter 操作。
-
ON在 hash join 的 build 阶段就能用user_id索引缩小右表扫描范围 -
WHERE无法驱动 join 策略,只能靠后续 filter 算子,统计估算也更容易偏差 - 多表连接时差异放大:比如
A INNER JOIN B ON ... INNER JOIN C ON B.id = C.b_id AND C.type = 'active',C.type放ON能避免无谓连接C表的无效行
ON 定义“怎么连”,WHERE 定义“要哪些”
这是最本质的分工:ON 是关系代数里的 theta-join 条件,决定两表哪些行配对;WHERE 是 selection 操作,在最终结果上做行级筛选。
-
ON必须出现在JOIN子句中,且只作用于当前两个表的匹配逻辑 -
WHERE作用于整个连接结果,可跨表引用、可含聚合或子查询(但需注意执行顺序) - 混合使用常见场景:外连接用
ON控制关联,再用WHERE过滤主表字段(如WHERE u.is_active = 1)——这不会丢行,因为条件不依赖右表
最容易被忽略的是:LEFT JOIN 后跟的 WHERE 条件一旦涉及右表非空约束(哪怕只是 WHERE o.id IS NOT NULL),就事实退化成 INNER JOIN。写之前先问一句:这个条件是“定义关联规则”,还是“筛选最终结果”?答案决定它该在哪。











