最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
为什么MySQL在关联查询时驱动表的选择直接影响索引效率
时间:2026-07-13 09:42:52 编辑:袖梨 来源:一聚教程网
驱动表选错会导致被驱动表索引失效;NLJ仅在被驱动表关联字段有索引时生效,索引只加速被驱动表单行查找,不加速驱动表遍历。
驱动表选错,被驱动表的索引根本用不上
MySQL的Index Nested-Loop Join(NLJ)只在被驱动表的关联字段有索引时才生效。如果优化器误把大表当驱动表、小表当被驱动表,而小表恰好没建索引——那整个JOIN就退化成Block Nested-Loop Join或Hash Join,索引形同虚设。
关键点在于:**索引只加速“被驱动表”的单行查找,不加速驱动表的遍历**。驱动表走全表扫描或范围扫描,被驱动表才靠索引定位匹配行。所以哪怕b.id上有主键索引,只要b被当成驱动表,这个索引在JOIN阶段就完全不会参与匹配逻辑。
- LEFT JOIN中左表固定是驱动表,所以
ON条件里右表的字段必须有索引 - INNER JOIN中优化器按WHERE过滤后的结果集大小选驱动表,不是按物理表大小——
WHERE status = 'active'后只剩100行的“大表”,也可能被选为驱动表 - 如果连接字段类型不一致(比如
INTvsVARCHAR),MySQL会隐式转换,导致被驱动表索引失效,即使建了也没用
EXPLAIN里看驱动顺序比看表名更可靠
EXPLAIN输出中,id相同且select_type为SIMPLE的行,从上到下就是实际执行顺序:上面的是驱动表,下面是被驱动表。别只盯着FROM a JOIN b就认定a是驱动表——优化器可能重排。
重点看type和Extra字段:
-
type为ALL或index→ 驱动表正在全表/索引扫描 -
type为ref/eq_ref/range→ 被驱动表走了索引查找 -
Extra含Using join buffer→ 没走索引,触发Block Nested-Loop Join -
Extra含Using where; Using index→ 被驱动表命中覆盖索引,效率最高
小表驱动大表 ≠ 物理小表,而是过滤后结果集最小
真正影响NLJ效率的,是驱动表最终要循环多少次。假设orders有1000万行,但WHERE created_at > '2026-06-01'后只剩50行;users只有10万行,但没加WHERE,全量参与。这时优化器大概率选orders当驱动表——外层只循环50次,每次用user_id索引查users,总开销远小于反过来。
- 用
SELECT COUNT(*)配合相同WHERE条件预估驱动表结果集大小 - 对驱动表的WHERE条件字段建索引,能进一步缩小其扫描范围
- 避免在驱动表上用
SELECT *,减少join_buffer内存压力,尤其当它意外变大时
被驱动表索引不是建了就完事,得看查询路径
即使user_id字段建了索引,如果JOIN条件写成ON CAST(o.user_id AS CHAR) = u.id,或者ON o.user_id + 0 = u.id,都会触发隐式转换,索引失效。同样,如果被驱动表需要回表(比如SELECT *但索引不是覆盖索引),性能也会打折扣。
- 确保JOIN字段类型完全一致:
TINYINT对TINYINT,VARCHAR(32)对VARCHAR(32),字符集也要相同 - 优先用主键或唯一索引做JOIN字段,避免二级索引+回表
- 若被驱动表需返回大量非索引列,考虑添加覆盖索引,例如
INDEX(user_id, name, email)
EXPLAIN就能暴露问题,但很多人直接跳过这步,转头去调join_buffer_size——方向错了,调再久也没用。
相关文章
- 王者荣耀世界零氪玩家如何生存 07-28
- 快手极速版怎么绑定手机号 07-28
- 明日方舟和轻松小熊联动活动内容一览 07-28
- 逆战未来黎明之光 逆战未来黎明之光玩法机制与新手入门指南 07-28
- 植物大战僵尸融合版毁灭土豆地雷介绍 07-28
- 逆战未来飓风之龙 逆战未来飓风之龙武器获取方法详解 07-28