explain中key为null但字段有索引,是因join字段collation_name不一致导致优化器弃用索引;须用show full columns或information_schema.columns比对字段collation、确认@@collation_connection对齐,并用alter table modify同时指定character set和collate修正。

EXPLAIN显示key为NULL但字段明明有索引,先查Collation是否对齐
这不是索引没建好,而是MySQL在JOIN前发现两边字段的collation_name不一致,主动弃用索引。别猜哪边错了,直接查三层:字段定义、连接层、字面量隐含规则。
逐条执行:
-
SHOW FULL COLUMNS FROM table1 LIKE 'join_col',看Collation列值 -
SHOW FULL COLUMNS FROM table2 LIKE 'join_col',比对是否**一字不差**(比如utf8mb4_0900_as_cs≠utf8mb4_unicode_ci) -
SELECT @@collation_connection,确认当前连接默认排序规则
只要任意一对不完全相同,就可能触发隐式转换,导致EXPLAIN中key为NULL、type变成ALL。
用INFORMATION_SCHEMA一次性对比两个表的JOIN字段
比反复敲SHOW FULL COLUMNS更高效,尤其当涉及多对关联字段时。
执行这条SQL:
SELECT table_name, column_name, character_set_name, collation_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_schema = 'your_db'
AND table_name IN ('table1', 'table2')
AND column_name IN ('join_col');
重点只看collation_name列——即使character_set_name都是utf8mb4,只要排序规则不同,MySQL就拒绝走索引。
注意:这个查询结果是实时的,不会受缓存干扰,比SHOW CREATE TABLE末尾的注释更可信。
ALTER TABLE MODIFY时漏掉CHARACTER SET或COLLATE都会白干
MySQL比较字符串时依赖的是排序规则(collation),不是字符集本身。只改一个,等于没改。
正确写法(必须同时指定):
ALTER TABLE table2 MODIFY join_col VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs;
错误写法(常见坑):
-
ALTER TABLE table2 CONVERT TO CHARACTER SET utf8mb4—— 只改表默认值,不碰已有字段的COLLATE -
ALTER TABLE table2 MODIFY join_col VARCHAR(64) COLLATE utf8mb4_0900_as_cs—— 漏了CHARACTER SET,MySQL可能按库默认补上不兼容值
改完立刻验证:SHOW CREATE TABLE table2,确认字段定义里同时出现CHARACTER SET utf8mb4和COLLATE utf8mb4_0900_as_cs。
改完表结构,查询还是慢?检查连接层collation_connection
就算两张表字段的COLLATE已完全一致,如果应用连进来时@@collation_connection不匹配,SQL里的字符串字面量(比如'abc')仍会被按错误规则解析,JOIN条件在优化器开始工作前就失真了。
验证方式:
SELECT @@character_set_client, @@collation_connection;
典型问题场景:
- JDBC连接串漏掉
&collationConnection=utf8mb4_0900_as_cs,只写了useUnicode=true&characterEncoding=utf8mb4 - Python pymysql传
charset='utf8'(不是utf8mb4),触发隐式降级 - 用
SET NAMES utf8mb4但没指定COLLATE,实际生效的是库默认排序规则
临时调试可加:SET NAMES utf8mb4 COLLATE utf8mb4_0900_as_cs,但上线必须从连接配置源头解决。
真正容易被忽略的是三层collation必须全部对齐:字段定义、连接层、字面量隐含规则。少对齐一层,索引就可能失效,且问题会随着数据量增长越来越隐蔽。











