join变慢主因是on字段无索引导致嵌套循环全表扫描;需确保字段类型一致、避免null、建复合索引遵循最左前缀,并用explain验证执行计划。

JOIN 字段没索引,查询直接变慢十倍
MySQL 的 JOIN 操作本身不慢,慢的是驱动表(左表)每扫一行,被驱动表(右表)都得全表扫描匹配一次。如果 ON 条件字段没索引,就会触发这种嵌套循环的暴力匹配。
实操建议:
- 检查
EXPLAIN输出中type列是否为ALL或index—— 这说明走了全表或全索引扫描,不是高效查找 - 确保
ON子句两边的字段类型完全一致(比如都是INT,不能一边是INT一边是VARCHAR),否则即使建了索引也用不上 - 复合索引要遵循最左前缀原则:若
ON a = b AND c = d,优先在被驱动表上建(b, d)索引,而不是只建b
小表驱动大表,但 MySQL 不一定听你的话
理论上应该让结果集更小的表做驱动表,减少外层循环次数。但 MySQL 的查询优化器会自己决定驱动顺序,STRAIGHT_JOIN 是唯一能强制指定的方式。
实操建议:
- 用
EXPLAIN FORMAT=TREE查看实际驱动顺序,别只看 SQL 里写的先后顺序 - 当优化器选错时(比如误判小表为大表),在
SELECT后加STRAIGHT_JOIN,并把预期的小表放前面 - 注意:
STRAIGHT_JOIN会禁用优化器重排,一旦数据分布变化,可能反而更差,适合稳定、已知规模的场景
临时表和排序导致 JOIN 性能雪崩
当 JOIN 后需要 GROUP BY、ORDER BY 或 SELECT * 且字段太多时,MySQL 可能创建隐式临时表,甚至落盘(Using temporary; Using filesort),IO 成为瓶颈。
实操建议:
- 只查真正需要的字段,避免
SELECT *,尤其不要跨表查大文本字段(如TEXT) - 如果必须排序,确保
ORDER BY字段在驱动表或被驱动表的索引中,并尽可能覆盖在同一个复合索引里(例如(join_key, sort_col)) - 观察
EXPLAIN中的Extra列,出现Using temporary就要警惕,优先考虑改写逻辑或加覆盖索引
关联字段存在 NULL,索引可能失效
当 ON t1.a = t2.b 中任意一边的字段允许 NULL,且实际数据中有大量 NULL 值,MySQL 可能放弃使用该字段上的索引——因为 B+ 树索引默认不存储 NULL,优化器估算选择性变差。
实操建议:
- 建表时尽量避免
JOIN字段设为NULLABLE;如业务允许,用0或特殊值替代NULL - 若无法修改表结构,可在
ON条件中显式排除NULL,例如t1.a = t2.b AND t1.a IS NOT NULL AND t2.b IS NOT NULL,帮助优化器判断可选索引范围 - 用
SHOW INDEX FROM table_name确认索引是否包含该字段,再结合SELECT COUNT(*) FROM t WHERE col IS NULL评估 NULL 比例










