驱动表是explain中rows小且type为ref或eq_ref的表,而非from顺序决定;小表驱动失效常见于on字段无索引、字段类型不一致、大表where未下推;需验证过滤后行数和索引使用情况。

因为驱动表决定外层循环次数,小表行数少,能直接压低总匹配开销——但这个“小”必须是WHERE过滤后的结果集小,不是建表时的物理行数小。
EXPLAIN里哪张表才是真正的驱动表
别看FROM顺序,要看EXPLAIN输出中rows列数值小、且type为ref或eq_ref的那张表。它才是优化器选的驱动表。
- 如果
rows值远大于你预期的“小表”行数,说明统计信息过期,该跑ANALYZE TABLE了 -
type = ALL且rows极大,基本可判定这张表被当成了被驱动表,且没走索引 - 对
LEFT JOIN,左表固定是驱动表,EXPLAIN里它的rows再大也改不了——这时候只能优化左表的WHERE条件或加索引
小表驱动失效的三个典型现场
你以为的小表,执行时根本没被当小表用,常见于:
- 被驱动表的
ON字段没索引:比如ON DATE(o.create_time) = '2026-04-23',函数导致索引失效,NLJ退化成全表扫描,小表驱动毫无意义 - 字段类型不一致:小表
user_id是BIGINT,大表user_id是VARCHAR,隐式转换让索引失效 - WHERE条件写在大表上却没下推:如
SELECT * FROM small s JOIN large l ON s.id = l.id WHERE l.status = 1,优化器可能先JOIN再过滤,导致驱动侧实际数据量暴增
什么时候该手动干预驱动顺序
当确认过滤后的小结果集没被自动选为驱动表,且你已排除索引和类型问题,才考虑强制干预:
- 用子查询封装小结果集:
SELECT * FROM (SELECT id FROM large WHERE status IN (1,2)) t JOIN small s ON t.id = s.id,让优化器一眼识别驱动侧规模 - 对
INNER JOIN,加STRAIGHT_JOIN:SELECT STRAIGHT_JOIN * FROM small s JOIN large l ON s.id = l.id - 避免在
STRAIGHT_JOIN里混用LEFT JOIN——它只控制JOIN顺序,不改变LEFT语义,容易写出逻辑错误
真正卡住性能的,从来不是“谁放前面”,而是“过滤后到底还剩几行”和“被驱动表那列到底走没走索引”。这两个问题不验证清楚,所有STRAIGHT_JOIN和子查询都是白忙。











