INNER JOIN只保留双方匹配的行,执行时先笛卡尔积再按ON过滤;LEFT JOIN强制保留左表所有行,右表无匹配则填NULL;ON控制关联,WHERE过滤结果,误将右表条件放WHERE会使LEFT JOIN退化为INNER JOIN。

JOIN(INNER JOIN)只保留双方都匹配的行
执行时,MySQL 会先对两张表做笛卡尔积的逻辑扫描,再根据 ON 条件过滤出匹配对。不满足条件的组合直接丢弃,不会出现在结果中。
常见错误现象:LEFT JOIN 写成 JOIN 后发现某些主表数据“消失”了——其实不是消失,是它根本没匹配上右表,被自然过滤掉了。
- 性能上通常最优,因为结果集最小,索引可双向利用(左表字段和右表字段上的索引都可能生效)
- 若右表连接字段无索引,
JOIN可能触发全表扫描,但优化器仍倾向走嵌套循环或哈希连接 - 语义等价于
FROM a, b WHERE a.id = b.a_id,但显式写INNER JOIN更清晰、更易维护
LEFT JOIN 以左表为基准,强制保留左表所有行
执行顺序是:先取出左表全部数据 → 对每一行,去右表查匹配记录 → 匹配成功则拼字段,失败则右表字段填 NULL。
关键点在于:即使 ON 条件在右表中永远不成立(比如 ON 1=0),左表数据也全在,右表全为 NULL。
- 如果在
WHERE子句里对右表字段加非空判断(如WHERE b.status = 'active'),会把原本NULL的行也过滤掉,实际效果退化为INNER JOIN - 右表索引作用较弱,优化器更依赖左表索引;右表连接字段没索引时,性能下降明显
- 多表 LEFT JOIN 时,连接顺序影响结果:先
A LEFT JOIN B,再用结果LEFT JOIN C,C 的匹配基于 A+B 的中间结果,不是原始 A
RIGHT JOIN 本质是 LEFT JOIN 的镜像,但容易混淆主从关系
执行逻辑与 LEFT JOIN 对称:先取右表全量 → 每行去左表找匹配 → 不匹配则左表字段为 NULL。
真实项目中极少直接写 RIGHT JOIN,因为可读性差,且多数人习惯从左往右读 SQL。遇到需要“以右表为主”的场景,更推荐调换表顺序 + 改用 LEFT JOIN。
-
SELECT * FROM a RIGHT JOIN b ON a.id = b.a_id等价于SELECT * FROM b LEFT JOIN a ON a.id = b.a_id - 当涉及三张及以上表时,混用
LEFT JOIN和RIGHT JOIN极易导致逻辑错乱,调试成本高 - MySQL 8.0+ 对
RIGHT JOIN的优化支持略弱于LEFT JOIN,尤其在复杂子查询嵌套中
ON 和 WHERE 的执行时机差异决定 NULL 是否被过滤
这是最容易踩坑的地方:很多人以为 LEFT JOIN ... ON b.x = 'val' 就能筛出右表特定值,其实不然。
ON 是连接阶段的条件,只控制“哪些右表行能跟当前左表行配对”;WHERE 是连接完成后的结果集过滤,此时右表字段已确定(可能是值,也可能是 NULL)。
- 写成
LEFT JOIN b ON a.id = b.a_id AND b.status = 'active':右表只拿status = 'active'的行参与连接,不匹配的仍保留左表 + 右表全NULL - 写成
LEFT JOIN b ON a.id = b.a_id WHERE b.status = 'active':先连完再过滤,b.status为NULL的行被整行剔除,结果等同于INNER JOIN - 想查“左表有但右表无 active 记录”的数据?得用
WHERE b.a_id IS NULL或WHERE b.status != 'active' OR b.status IS NULL,但注意 NULL 判断必须显式写
真正难的不是语法,而是每次写 JOIN 前,你得在脑子里跑一遍它的执行流:哪张表先加载?匹配失败怎么填?过滤发生在连接前还是连接后?漏掉这个思维步骤,NULL 就会悄无声息地吃掉你的数据。


















