驱动表选错会导致嵌套循环次数爆炸,核心是驱动表每行触发被驱动表一次查找;若驱动表过滤后10万行、被驱动表1万行,则最坏需10亿次匹配。

驱动表选错直接导致嵌套循环次数爆炸
MySQL 默认用 Nested Loop Join(NLJ)执行 JOIN,核心逻辑是:**驱动表每返回一行,就被动表就要完整查一次**。如果驱动表过滤后有 10 万行,被驱动表哪怕只有 1 万行,最坏也要做 10 万 × 1 万 = 10 亿次匹配操作——这还没算索引查找开销。
常见错误现象:EXPLAIN 显示某张表的 rows 值远高于其他表,但它却被优化器选为驱动表;Extra 列出现 Using join buffer (Block Nested Loop),说明已 fallback 到更慢的 BNLJ。
- 驱动表的
rows值来自 WHERE 条件过滤后的估算值,不是表总行数 - 没加 WHERE 的大表,哪怕物理行数少,也可能因
rows=总行数被误判为“大表” - 统计信息过期(
ANALYZE TABLE没跑)时,rows估算严重失真
被驱动表没索引时,驱动表越小反而越慢
“小表驱动大表”有个硬前提:**被驱动表的 JOIN 字段必须有可用索引**。否则,驱动表每行都会触发对被驱动表的全表扫描——这时驱动表越小,只是把“每次扫全表”的次数变少了,但单次代价依然极高。
使用场景:你写 SELECT * FROM orders o JOIN users u ON o.user_id = u.id,若 users.id 是主键但 orders.user_id 没索引,MySQL 可能仍选 orders 当驱动表(因它有更多过滤条件),结果是:orders 每行都扫一遍 users 全表。
- 确认索引是否生效:
EXPLAIN中被驱动表的type必须是eq_ref或ref,不能是ALL或index -
users表有主键,但orders.user_id字段本身必须单独建索引才能加速反向查找 - 复合索引要注意顺序:比如
WHERE status = 'paid' AND user_id = ?,索引应为(status, user_id),而非反过来
LEFT JOIN 强制左表为驱动表,但业务上未必合理
LEFT JOIN 的语义决定了左表一定是驱动表,无法由优化器重排。如果左表是千万级订单表,右表是百行配置表,那 MySQL 不得不先扫完全部订单,再逐条去配表里找——即使最终只返回几十行有效记录。
真实踩坑点:有人把 FROM large_table LEFT JOIN small_table 当成“先查大表再补小表信息”,却忽略了中间结果集膨胀问题。只要 large_table 没强 WHERE 过滤,rows 就是千万级,性能必然崩。
- 检查是否真需要 LEFT JOIN:如果业务允许无匹配也丢弃(即只取有配置的订单),改用
INNER JOIN让优化器自由选驱动表 - 实在要用 LEFT JOIN,务必在左表加高选择性 WHERE,比如
WHERE created_at > '2026-09-01',把rows压到千级别以下 - 避免在 LEFT JOIN 的右表字段上写 WHERE 条件(如
AND small_table.enabled = 1),这会把 LEFT JOIN 退化为 INNER JOIN,且可能让优化器误判执行顺序
MySQL 8.0+ 的 Hash Join 并没绕过“小表优先”原则
Hash Join 确实不再依赖索引,但它内部仍是“用小表建哈希表、大表去探测”。如果优化器选错驱动表,小表变成大表,哈希表就可能撑爆内存,触发磁盘溢出(Temp file read/write),速度比 NLJ 还慢。
验证方式:EXPLAIN FORMAT=TREE 会显示 -> Hash join 及其构建侧(build side)和探测侧(probe side)。构建侧必须是估算行数更小的那个表。
- Hash Join 对内存敏感:
join_buffer_size太小会导致频繁分批构建哈希表 - 并非所有等值 JOIN 都能自动走 Hash Join:仅当连接字段类型完全一致、无隐式转换、且优化器判定哈希收益更高时才启用
- 用
STRAIGHT_JOIN强制顺序时,Hash Join 仍会遵守你指定的 build/probe 关系,但不会校验合理性
实际调优时,最常被忽略的是:驱动表的“小”,永远指 WHERE 过滤后的 rows,而不是你心里觉得“这张表数据量少”。一张 10 行的字典表,如果没有 WHERE 条件,它在 JOIN 中的 rows 就是 10;而一张 1000 万行的订单表,加上 WHERE order_time > '2026-09-04' 后 rows 估算为 500,它才是真正的“小表”。











