因b+树索引依赖严格字符串比较逻辑,collation不一致会导致相同字符串被判定不等,优化器为保证结果正确性主动弃用索引,降级为type:all;须用show full columns或information_schema.columns比对关联字段collation_name是否完全一致,并通过alter table modify同时指定character set与collate统一修正。

为什么字符集或COLLATION不一致会让索引失效
MySQL 的 B+ 树索引依赖严格、可预测的字符串比较逻辑。一旦 JOIN 字段的 CHARACTER SET 或 COLLATION 不同,比如一边是 utf8mb4_0900_as_cs(区分大小写、带 Unicode 12.1 排序),另一边是 utf8mb4_unicode_ci(不区分大小写、旧版排序规则),相同字符串在两个规则下可能被判定为“不等”。优化器无法保证用索引扫描的结果和全表比对一致,于是主动弃用索引,降级为 type: ALL 或 Using join buffer。
怎么一眼确认是不是字符集/COLLATION 惹的祸
别猜,直接查定义:
- 运行
SHOW FULL COLUMNS FROM t1 LIKE 'user_id'和SHOW FULL COLUMNS FROM t2 LIKE 'user_id',比对两行的Collation值是否**完全一致**(注意大小写、下划线、版本后缀) - 更省事:查
information_schema.COLUMNS一次性对比:SELECT table_name, column_name, character_set_name, collation_name FROM information_schema.COLUMNS WHERE table_name IN ('t1','t2') AND column_name = 'user_id'; - 只要
character_set_name或collation_name任一不同,就是根因;哪怕都是utf8mb4,utf8mb4_general_ci ≠ utf8mb4_0900_as_cs
在 ON 子句里加 COLLATE 能不能临时绕过
不能。写成 t1.name = t2.name COLLATE utf8mb4_0900_as_cs 或 CONVERT(t2.name USING utf8mb4) 只是语法上通过,实际仍不走索引:
- 这类转换是运行时行为,优化器无法下推,
t2.name上的索引完全不可用 - EXPLAIN 里依然显示
key: NULL、type: ALL,甚至可能多出Using temporary - 即使某次“侥幸”走了索引,执行计划也不稳定,上线后极易退化
真正有效的修复方式
必须统一字段定义本身:
- 先确定目标
COLLATION,例如主表用的是utf8mb4_0900_as_cs,那就全部对齐 - 执行
ALTER TABLE t2 MODIFY user_id VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs—— 注意:CHARACTER SET和COLLATE必须同时指定,只改一个无效 - 改完立刻运行
SHOW CREATE TABLE t2确认字段定义末尾已更新,别信SHOW FULL COLUMNS的缓存结果 - 外键、UNION 列、全文索引字段也得同步检查——它们不显式出现在 JOIN 条件里,但数据库内部照样做字符比对
最容易被忽略的是连接层:就算所有字段都改对了,如果应用连进来时 @@collation_connection 是 latin1_swedish_ci,SQL 中的字面量(比如 'admin')仍会按错误规则解释,JOIN 条件在解析前就失真。










