mysql join执行顺序由优化器决定,非sql书写顺序;逻辑上严格遵循from→on→where→group by→having→select→order by→limit,其中on在join过程中过滤关联条件,where在连接后二次筛选,错放left join的条件会导致其退化为inner join。

MySQL JOIN查询的执行顺序不是按SQL书写顺序来的,而是由优化器决定的;但逻辑上存在严格固定的阶段先后关系,关键在于分清「物理执行顺序」和「语义执行顺序」。
EXPLAIN结果的table列顺序就是真实JOIN物理顺序
EXPLAIN输出的每一行对应一个表,table列从上到下,是MySQL「从下往上」实际执行JOIN的顺序。最下面那行是驱动表(先查),最上面那行是最后被关联的被驱动表。
- 比如
EXPLAIN SELECT * FROM A LEFT JOIN B ON ... JOIN C ON ...返回三行,table列为A、B、C(从上到下),说明物理执行顺序是:先查C→ 再用C匹配B→ 最后用中间结果匹配A - 哪怕你写的是
A LEFT JOIN B JOIN C,优化器也可能把C提前——只要它小、有好索引、过滤强 - 想强制顺序?加
STRAIGHT_JOIN,但只对INNER JOIN生效,且会绕过优化器,慎用
ON条件永远在WHERE之前执行,且语义不可互换
ON和JOIN是一体的,属于FROM阶段的一部分;WHERE是之后对已连接结果的二次过滤。这对LEFT JOIN尤其致命。
-
LEFT JOIN users ON orders.user_id = users.id AND users.status = 'active':保留所有订单,右表只匹配status = 'active'的用户,不匹配的users.*为NULL -
LEFT JOIN users ON orders.user_id = users.id WHERE users.status = 'active':先完成LEFT JOIN(含NULL行),再用WHERE筛掉所有users.status不等于'active'的行——包括users.status IS NULL的行,结果等价于INNER JOIN - 多表时,每个
ON只约束紧邻右侧的表,ON a.x = b.y AND b.z > 10中的b.z > 10是在关联B时就过滤,不是等到最后扫全量
完整语义执行流程:FROM → ON → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
这是SQL标准定义的逻辑处理流,MySQL严格遵循。理解这个链条,才能判断条件该放哪、别名能不能用、聚合函数在哪能写。
-
FROM/JOIN+ON:生成虚拟中间表(vt),LEFT JOIN在此阶段补NULL行 -
WHERE:对vt做行级过滤,此时还不能用SELECT里的别名,也不能用SUM()等聚合函数 -
GROUP BY:对WHERE后的结果分组,HAVING才可引用聚合函数 -
SELECT定义的别名,只有ORDER BY能直接用,WHERE/GROUP BY/HAVING都不能
真正容易被忽略的是:优化器重排表顺序时,ON条件仍绑定原位置的左右表,不会随物理顺序迁移;而WHERE条件一旦写错位置,LEFT JOIN就 silently 变成 INNER JOIN——这种bug线上很难察觉,只能靠EXPLAIN + 数据校验双保险。











