必须统一字段类型、字符集和校对规则(COLLATION),否则MySQL强制隐式转换导致索引失效,EXPLAIN中type为ALL;需用SHOW FULL COLUMNS或information_schema比对Data_Type、Character_Set、Collation三者是否完全一致,且ALTER TABLE修改时须同时指定CHARACTER SET和COLLATE,连接层@@collation_connection也必须对齐。

直接结论:不是加索引就能解决,而是必须统一字段类型、字符集和校对规则(COLLATION),否则MySQL会强制隐式转换,索引完全失效,EXPLAIN里必然出现type: ALL。
怎么确认是不是类型/字符集/COLLATION不一致?
别靠猜,用这两条命令直接比对定义:
-
SHOW FULL COLUMNS FROM table_a LIKE 'user_id'和SHOW FULL COLUMNS FROM table_b LIKE 'user_id',重点看三列:Data_Type、Collation、Character_Set - 或者一次性查:
SELECT table_name, column_name, character_set_name, collation_name, data_type FROM information_schema.COLUMNS WHERE table_name IN ('table_a', 'table_b') AND column_name = 'user_id'; - 只要其中任意一项不一致——比如一边是
BIGINT、另一边是VARCHAR(20);或都是VARCHAR但collation_name一个是utf8mb4_0900_as_cs、另一个是utf8mb4_unicode_ci——就是根因
为什么在ON里加CAST或COLLATE没用?
因为运行时转换无法下推到索引层,优化器根本不会考虑走索引:
-
ON CAST(t1.id AS CHAR) = t2.user_id→t2.user_id上的索引失效 -
ON t1.name COLLATE utf8mb4_0900_as_cs = t2.name COLLATE utf8mb4_0900_as_cs→ 语法通过,但key仍为NULL,type还是ALL - 真正起作用的是字段定义本身,不是SQL里的临时修饰
ALTER TABLE改字段的正确写法是什么?
必须同时指定CHARACTER SET和COLLATE,且目标值要和关联表字段完全一致:
- 错误写法:
ALTER TABLE table_b MODIFY user_id VARCHAR(20) CHARACTER SET utf8mb4;(只改字符集,COLLATION可能被补默认值) - 正确写法:
ALTER TABLE table_b MODIFY user_id VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs; - 改完立刻验证:
SHOW CREATE TABLE table_b;,不能只信SHOW FULL COLUMNS - 大表操作前加
ALGORITHM=INPLACE(MySQL 8.0+支持时)可减少锁表时间
容易被忽略的连接层陷阱
就算表结构全对齐了,如果客户端连接时的@@collation_connection不匹配,字面量(如'123')仍会被错误解释,JOIN条件在解析阶段就失真:
- 查当前连接设置:
SELECT @@collation_connection; - 确保它和字段的
collation_name一致,否则在应用连接字符串里显式指定collation=utf8mb4_0900_as_cs - 外键、UNION、全文索引字段也受同一套规则约束,不能只改JOIN字段
最麻烦的点往往不在SQL本身,而在于你改完一张表后,发现另一张表的字段定义、连接参数、甚至存储过程里的字面量都还卡在旧规则里——这种多层嵌套不一致,才是让EXPLAIN反复显示key: NULL的真正原因。


















