MySQL优化器决定驱动表而非JOIN语法,STRAIGHT_JOIN是唯一强制连接顺序的方式;隐式类型转换会导致索引失效,比驱动表选择错误更隐蔽。

左连接和右连接在执行计划里本质是一样的
MySQL 优化器不会因为写了 LEFT JOIN 就强制左边表做驱动表,也不会因为写了 RIGHT JOIN 就固定右边表驱动。它只看统计信息、索引、WHERE 条件和成本估算——最终选谁当驱动表,由优化器决定。你写 A LEFT JOIN B ON A.id = B.a_id,和写 B RIGHT JOIN A ON A.id = B.a_id,生成的执行计划通常完全一致。
真正影响性能的是「谁被选为驱动表」,而不是 JOIN 关键字本身。如果你观察到左右写法执行时间不同,大概率是某次查询碰巧触发了不同的索引选择或临时表策略,不是语法导致的固有差异。
Nested Loop Join 中驱动表小 ≠ 一定快
很多人认为“小表驱动大表就快”,但 MySQL 的 Nested Loop 实际依赖的是「驱动表结果集的行数 × 被驱动表单行匹配耗时」。这个“小”,指的是经过 WHERE 过滤后实际参与循环的行数,不是原表总行数。
- 如果
A表有 100 万行,但WHERE A.status = 'active'只返回 10 行,而B表只有 1 万行但没索引支持ON条件,那用A驱动反而更慢——因为每次查B都要全表扫描 - 驱动表字段上有高选择性索引,且被驱动表的
ON字段也有对应索引(最好是联合索引覆盖查询列),才能让每次循环变成一次快速索引查找 -
EXPLAIN输出里的type列如果是ALL或index,基本说明被驱动表没走好索引,这时候换驱动表可能没用,得先加索引
如何干预驱动表选择:STRAIGHT_JOIN 是唯一可靠方式
MySQL 不提供 FORCE LEFT JOIN 这种语法,STRAIGHT_JOIN 是唯一能明确指定连接顺序的手段。它强制按 SQL 中表出现的顺序进行嵌套循环,跳过优化器的重排序逻辑。
使用场景很具体:
- 你知道驱动表过滤后只剩几十行,且被驱动表有完美索引,但优化器误判选了反向顺序
- 执行计划反复波动,你想先锁定顺序做性能基线对比
-
STRAIGHT_JOIN必须写在SELECT后、第一个表前,例如:SELECT STRAIGHT_JOIN * FROM A JOIN B ON A.id = B.a_id - 注意:一旦用了
STRAIGHT_JOIN,后续所有 JOIN 都按书写顺序执行,不能只控制某一对
容易被忽略的隐式转换陷阱
即使驱动表很小、索引也齐全,如果 ON 条件存在隐式类型转换,比如 A.id 是 INT,B.a_id 是 VARCHAR,MySQL 会把 A.id 转成字符串去比对——这会导致 B.a_id 上的索引失效(无法做最左前缀匹配),被驱动表退化为全表扫描。
这类问题在 EXPLAIN 里表现为 type: ALL 或 key: NULL,但你检查建表语句才发现字段类型不一致。修复方式只有统一类型,或者在查询中显式 CAST(B.a_id AS SIGNED)(不推荐,仍可能绕过索引)。
连接字段类型不一致,比驱动表选错更隐蔽,也更难排查。



















