JOIN失败主因是字段COLLATION_NAME不兼容,需查INFORMATION_SCHEMA.COLUMNS确认并ALTER TABLE MODIFY同步字符集与校对规则,连接层collation也须对齐。

JOIN失败大概率不是SQL写错了,而是两边字段的COLLATION_NAME不兼容——哪怕字符集都是utf8mb4,utf8mb4_unicode_ci和utf8mb4_0900_as_cs也不能直接等值比较。
查清两个JOIN字段的真实COLLATION
别信建表语句里写的默认值,也别只看SHOW CREATE TABLE末尾的注释。真实生效的校对规则藏在INFORMATION_SCHEMA.COLUMNS里:
- 执行
SELECT COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'db1' AND TABLE_NAME = 't1' AND COLUMN_NAME = 'code'; - 再执行同结构查
db2.t2的code字段 - 逐字比对两行的
COLLATION_NAME是否完全一致(比如utf8mb4_0900_ai_ci≠utf8mb4_unicode_ci)
ALTER TABLE MODIFY才是永久解法
在ON子句里加COLLATE只是临时绕过,索引会失效,ORM也不认。真正要改的是字段定义本身:
- 必须同时指定
CHARACTER SET和COLLATE:ALTER TABLE t2 MODIFY code VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; - 不能只写
CONVERT TO CHARACTER SET utf8mb4——它不改已有字段的COLLATE - 改完立刻跑
SHOW CREATE TABLE t2确认,别只信SHOW FULL COLUMNS缓存显示 - 大表操作前加
ALGORITHM=INPLACE(MySQL 8.0+),但全文索引或外键存在时可能不支持
连接层collation必须同步对齐
就算表字段全改对了,如果应用连上来时@@collation_connection是错的,SQL里的字面量(比如'abc')仍会被按错误规则解析:
- 查当前连接状态:
SELECT @@character_set_client, @@collation_connection; - JDBC连接串漏掉
&collationConnection=utf8mb4_0900_ai_ci,只写了useUnicode=true&characterEncoding=utf8mb4就容易中招 - Python pymysql传
charset='utf8'(不是utf8mb4)也会触发隐式降级 - 用
SET NAMES utf8mb4 COLLATE utf8mb4_0900_ai_ci替代SET NAMES utf8mb4
临时方案只适用于调试,且必须加在表达式上
上线前来不及改表?可以临时加COLLATE,但写法极关键:
- 正确:
ON t1.code COLLATE utf8mb4_0900_ai_ci = t2.code COLLATE utf8mb4_0900_ai_ci - 错误:
ON t1.code = t2.code COLLATE utf8mb4_0900_ai_ci(只改一边,MySQL仍会推导冲突) - 子查询也要处理:
(SELECT code COLLATE utf8mb4_0900_ai_ci FROM t2) - 注意:这种写法会让
t2.code上的索引失效,EXPLAIN里key变NULL,仅限一次性脚本或紧急回滚
最常被忽略的点是:外键、UNION、GROUP BY、GROUP_CONCAT全都依赖字段COLLATION做字符串比较。一个字段没对齐,其他地方就可能静默出错——排查时得把整条数据链路里所有参与比较的字符串字段都拉出来核对一遍。

















