EXPLAIN中type=ALL、key=NULL,很可能是COLLATION不一致导致索引失效;因不同校对规则下字符串比较逻辑不同,优化器为保证语义正确性主动弃用索引,必须统一字段及连接层的character_set和collation才能修复。

EXPLAIN里type=ALL、key=NULL,基本就是COLLATION不一致
这不是“可能慢”,是MySQL优化器主动弃用索引。B+树索引依赖严格有序比较,而不同COLLATION下,相同字符串在排序、大小写、重音、emoji等处理上逻辑不同(比如utf8mb4_unicode_ci和utf8mb4_0900_as_cs对德语“ß”的判定就不同)。优化器无法保证索引扫描结果的语义正确性,只能退化为全表扫描或Using join buffer。
查字段定义比猜快十倍:SHOW FULL COLUMNS和INFORMATION_SCHEMA.COLUMNS
别靠经验判断,直接查真实定义:
-
SHOW FULL COLUMNS FROM t1 LIKE 'user_id'→ 看Collation列值 -
SHOW FULL COLUMNS FROM t2 LIKE 'user_id'→ 对比是否**一字不差** - 更省事:
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_0900_as_cs vs utf8mb4_unicode_ci),照样触发隐式转换。
ALTER TABLE MODIFY才是真解法,ON里加COLLATE没用
在ON子句里硬写t1.name COLLATE utf8mb4_0900_as_cs = t2.name COLLATE utf8mb4_0900_as_cs,语法能过,但索引依然不走——因为这是运行时转换,优化器无法下推,t2.name上的索引根本不会被命中。
必须改字段定义本身,且要同时指定两项:
- ✅ 正确:
ALTER TABLE t2 MODIFY user_id VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs; - ❌ 错误:
ALTER TABLE t2 CONVERT TO CHARACTER SET utf8mb4;(只改表默认值,不动字段) - ❌ 错误:
ALTER TABLE t2 MODIFY user_id VARCHAR(50) COLLATE utf8mb4_0900_as_cs;(漏了CHARACTER SET)
改完立刻执行SHOW CREATE TABLE t2确认字段定义已更新,别信SHOW FULL COLUMNS的缓存显示。
连接层collation不统一,改表也白搭
就算所有表字段都统一成utf8mb4_0900_as_cs,如果应用连上来时@@collation_connection是utf8mb4_unicode_ci或latin1_swedish_ci,SQL里的字面量(比如'张三')仍按错误规则解释,JOIN条件在解析前就失真。
验证当前连接状态:SELECT @@collation_connection;,必要时在连接初始化时显式设置:SET NAMES utf8mb4 COLLATE utf8mb4_0900_as_cs;
真正容易被忽略的是:外键约束、UNION、全文索引字段也会因COLLATION不一致报错或失效,它们不一定出现在你的JOIN语句里,但数据库内部仍会做隐式比对。


















