不加索引的JOIN字段会导致被驱动表全表扫描,性能断崖下跌;ON字段必须在被驱动表上单独建索引(如t2.id),且类型、长度、字符集须严格一致,否则隐式转换致索引失效。

不加索引的 JOIN 字段,等于在生产环境裸奔——只要 EXPLAIN 里看到被驱动表的 type 是 ALL,基本就是没走索引,正在全表扫描。
为什么 ON 字段必须单独建索引?
MySQL 默认用 Nested-Loop Join:驱动表每返回一行,就被驱动表就得逐行比对一次。如果被驱动表没索引,就只能全表扫一遍。10 万行驱动 × 100 万行被驱动 = 1000 亿次比对——不是“慢一点”,是查不出结果。
-
ON t1.user_id = t2.id要求t1.user_id和t2.id都得有索引;少一个,t2就大概率退化为ALL - LEFT JOIN 中左表固定为驱动表,右表是被驱动表——很多人只给左表加了索引,却忘了右表
rule_id也要建idx_rule_id - 联合索引不能“兼职”:比如
INDEX(status, user_id)对ON u.id = o.user_id无效,因为user_id不是最左前缀
怎么确认索引真的生效了?
别信感觉,看 EXPLAIN 输出里的 type 和 key 列:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 被驱动表出现
type: ALL或type: index(非覆盖索引),说明没走对路 - 理想状态是
type: ref、eq_ref或range,且key列明确显示用了哪个索引 - 注意
key_len:如果值比预期小(比如VARCHAR(50)字段只用了 1 字节),可能是字符集不一致或隐式转换导致索引截断
哪些地方最容易漏建索引?
最容易被忽略的不是“有没有索引”,而是“索引建在哪张表、哪个字段、什么顺序”:
- RIGHT JOIN 的左表、LEFT JOIN 的右表——这两侧的 ON 字段常被遗忘
- 多表 JOIN 时中间表(比如
A JOIN B JOIN C中的B)既是某次 JOIN 的被驱动表,又是另一次的驱动表,它的关联字段要双向覆盖 - 字段类型不一致:哪怕只是
INT和UNSIGNED INT、VARCHAR(32)和VARCHAR(100),都会触发隐式转换,让索引完全失效 - 存储过程中生成的临时表:MySQL 不会自动加索引,必须显式
ALTER TABLE tmp ADD INDEX idx_xxx (col),且要在插入数据前执行
最麻烦的不是建错索引,而是建了索引但字段类型/字符集/表达式写法不对,导致 MySQL 根本不认——这种失效无声无息,EXPLAIN 看起来一切正常,实际还是全表扫。

















