MySQL JOIN 中 ON 条件 vs WHERE 条件的区别

1. 语义区别(LEFT JOIN 时差异最明显)

-- 方式1: 条件在 ON 中
SELECT * FROM 订单表 m
LEFT JOIN 客户表 p ON p.ID = m.CUSTOMER_ID AND p.STATUS = 1

-- 方式2: 条件在 WHERE 中
SELECT * FROM 订单表 m
LEFT JOIN 客户表 p ON p.ID = m.CUSTOMER_ID
WHERE p.STATUS = 1
方式 结果
ON 中 保留所有订单,不满足 STATUS=1 的客户字段显示 NULL
WHERE 中 过滤掉不满足条件的行,LEFT JOIN 退化成 INNER JOIN

2. 执行顺序

FROM → ON → JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
  • ON:在 JOIN 生成临时表时 过滤
  • WHERE:在临时表 生成后 过滤

3. 性能区别

INNER JOIN 时:几乎无差别

-- 这两个等价,优化器会生成相同的执行计划
SELECT * FROM m INNER JOIN p ON p.ID = m.PRD_ID AND p.SEX = 'M'
SELECT * FROM m INNER JOIN p ON p.ID = m.PRD_ID WHERE p.SEX = 'M'

MySQL 优化器会自动将 WHERE 条件下推到 ON 中。

LEFT JOIN 时:ON 更优

-- ✅ 推荐:条件在 ON 中,减少中间结果集
SELECT * FROM m
LEFT JOIN p ON p.ID = m.PRD_ID AND p.DELETE_FLAG = 0

-- ❌ 不推荐:先生成大临时表,再过滤
SELECT * FROM m
LEFT JOIN p ON p.ID = m.PRD_ID
WHERE p.DELETE_FLAG = 0 OR p.ID IS NULL  -- 还要处理 NULL 情况
对比项 ON 条件 WHERE 条件
临时表大小 更小(提前过滤) 更大(全量 join 后过滤)
索引利用 可用于 join 优化 join 后再扫描
NULL 处理 自动保留主表行 需要额外处理

4. 实际建议

-- ✅ 正确写法:关联条件 + 过滤条件都放 ON
LEFT JOIN tb_product_dev_info p 
    ON p.ID = m.PRD_ID 
    AND p.DELETE_FLAG = 0 
    AND p.IS_OUT = 0

-- ❌ 避免:WHERE 中过滤 LEFT JOIN 的表
LEFT JOIN tb_product_dev_info p ON p.ID = m.PRD_ID
WHERE p.DELETE_FLAG = 0  -- 会把 LEFT JOIN 变成 INNER JOIN

5. 总结

场景 推荐 原因
INNER JOIN 都行 优化器会自动优化
LEFT JOIN 过滤右表 ON 保持 LEFT JOIN 语义,性能更好
LEFT JOIN 过滤左表 WHERE ON 中过滤左表无效

觉得内容还不错?打赏个钢镚鼓励鼓励!!👍