mysql解析sql时若子查询与外层字段collation不兼容(如utf8mb4_unicode_ci vs utf8mb4_0900_ai_ci),直接报illegal mix of collations错误;convert不可用于子查询整体,须作用于具体列;连接层字符集(如character_set_client)不匹配会导致源头失真;collate比convert更安全高效,且collation不一致在explain中不报错却致全表扫描。

MySQL执行=或JOIN时直接拒绝比较
不是数据内容错了,是MySQL在解析SQL阶段就卡住了:当子查询返回的字段和外层字段的COLLATION不兼容(比如一边是utf8mb4_unicode_ci,另一边是utf8mb4_0900_ai_ci),它连“相等”这个动作都不会执行,直接抛出Illegal mix of collations错误。
CONVERT不能套在子查询外面
常见错误写法:CONVERT((SELECT name FROM t2), USING utf8mb4)——这语法不合法,MySQL报错ERROR 1064。它只允许对表达式做转换,不是对子查询语句块。
正确做法必须把CONVERT或COLLATE落在具体列上:
(SELECT CONVERT(name USING utf8mb4) FROM t2)(SELECT name COLLATE utf8mb4_unicode_ci FROM t2)- 多列就得每列都加:
(SELECT id, code COLLATE utf8mb4_unicode_ci FROM t2)
连接层字符集污染会让修复白做
就算表结构全改成utf8mb4、所有字段都加了COLLATE,只要客户端连接时character_set_client还是latin1或utf8(即utf8mb3),MySQL会在SQL解析前就把参数强制转码,导致子查询里的中文从源头就失真。
查真实连接状态用:
SELECT @@character_set_client, @@character_set_connection, @@character_set_results;
Java JDBC必须带:?useUnicode=true&characterEncoding=utf8mb4&collationConnection=utf8mb4_0900_as_cs
Python pymysql必须传:charset='utf8mb4',写'utf8'会掉进陷阱
COLLATE比CONVERT更轻量且安全
如果两边字符集都是utf8mb4,只是排序规则不同,优先用COLLATE而不是CONVERT:
-
COLLATE不改变存储编码,无截断风险,性能更好 -
CONVERT可能触发隐式转换,让索引失效,甚至引发Using temporary; Using filesort - 必须附着在字段后:
t2.code COLLATE utf8mb4_unicode_ci,不能只写COLLATE utf8mb4_unicode_ci
真正容易被忽略的是:COLLATION不一致的问题,在EXPLAIN里往往不报错,但会悄悄退化成全表扫描——等你看到rows列显示几百万、几亿时,已经晚了。











