COLLATION不一致会导致MySQL优化器弃用索引,引发全表扫描;需通过information_schema比对collation_name是否完全一致,修改字段定义时必须同时指定CHARACTER SET和COLLATE,且连接层collation也须统一。

EXPLAIN里type=ALL、key=NULL,基本就是COLLATION不一致
这不是“可能慢”,是MySQL优化器主动弃用索引。B+树依赖严格有序比较,而不同COLLATION下,相同字符串在大小写、重音、emoji甚至德语“ß”的判定上逻辑不同(比如utf8mb4_unicode_ci和utf8mb4_0900_as_cs)。优化器无法保证索引扫描结果的语义正确性,只能退化为全表扫描或Using join buffer。
怎么快速确认是不是字符集或COLLATION惹的祸
别靠经验猜,直接查真实定义:
- 执行
SHOW FULL COLUMNS FROM t1 LIKE 'user_id'和SHOW FULL COLUMNS FROM t2 LIKE 'user_id',比对两行的Collation列值是否**一字不差** - 更省事:一次性对比两个表字段定义:
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_csvsutf8mb4_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;
最容易被忽略的是:这些校对规则差异不只影响显式JOIN,外键约束、UNION结果集、全文索引字段的MATCH AGAINST同样会因COLLATION不一致报错或失效——它们都在数据库内部做隐式比对,没人帮你兜底。

















