根本原因是字段collation与连接层字符集不一致,需统一为utf8mb4_unicode_ci等兼容排序规则,并在set names、临时表、字符串操作中显式指定,alter table修改字段collation才是治本之策。

存储过程里中文变问号、Illegal mix of collations 报错、索引失效——根本不是语法写错了,而是字段 COLLATION 和连接层字符集没对齐,只改一边白忙活。
查清字段真实 COLLATION 是第一步
别信建表语句里写的默认值,字段可能被单独覆盖过。MySQL 8.0 对隐式转换更保守,只要两边 COLLATION 不同,JOIN、WHERE、FIND_IN_SET 都会直接报错。
- 执行
SELECT TABLE_NAME, COLUMN_NAME, COLLATION_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'your_db' AND COLUMN_NAME IN ('ref_id', 'name') AND COLLATION_NAME IS NOT NULL;,把实际用的排序规则打出来 - 特别注意
utf8_unicode_ci和utf8mb4_unicode_ci混用——它们不兼容,哪怕语义差不多,MySQL 也不允许隐式转换 -
SHOW CREATE TABLE看的是表级定义,但字段级COLLATE可能单独写了,比如VARCHAR(50) COLLATE utf8_general_ci,这种优先级更高
SET NAMES 必须带 COLLATE,不能只写 utf8mb4
很多同学执行了 SET NAMES utf8mb4 还是乱码,问题就出在这儿:它只设了字符集,没设排序规则。而存储过程里字符串字面量(比如 '张三')的 COLLATION 默认继承连接层,不是字段的。
- 正确写法是:
SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;(或跟你字段一致的 collation,比如utf8_unicode_ci) - 命令行客户端启动时加参数:
mysql --default-character-set=utf8mb4 --collation-server=utf8mb4_unicode_ci -u root -p - 脚本批量建过程,第一行必须是
SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;,否则CREATE PROCEDURE语句里的中文在存入mysql.proc表时就已损坏
存储过程内所有字符串操作都要显式对齐 COLLATION
CONCAT、WHERE 条件、临时表字段、变量赋值——只要涉及字符串比较或拼接,MySQL 都会按参数中「最高优先级」的 COLLATION 输出结果。一旦和目标字段不一致,要么报错,要么索引失效。
- WHERE 条件写成:
WHERE username = '张三' COLLATE utf8mb4_unicode_ci,别用_utf8mb4'张三' COLLATE ...这种冗余前缀 - 拼接字符串:
CONCAT('ID:', id) COLLATE utf8mb4_unicode_ci - 声明临时表字段时明确指定:
tmp_name VARCHAR(100) COLLATE utf8mb4_unicode_ci - FIND_IN_SET() 两边都要加:
FIND_IN_SET(col1 COLLATE utf8mb4_unicode_ci, @var COLLATE utf8mb4_unicode_ci)
ALTER TABLE 修改字段 COLLATION 是唯一治本方式
临时加 COLLATE 能绕过单条 SQL 报错,但不解决数据层不一致。长期靠显式标注,维护成本高、易遗漏、性能差。
- 修复语句:
ALTER TABLE t MODIFY ref_id CHAR(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - TEXT 类型字段同样要改:
MODIFY content TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 如果字段有索引前缀(比如
VARCHAR(500)但只索引前 191 字),注意utf8mb4_0900_ai_ci的索引长度计算更严格,可能需调小前缀长度,否则ALTER会失败
最容易被忽略的点:存储过程执行时用的是「调用时」的连接上下文,不是「创建时」的。哪怕你建过程前设对了,应用连上来用的是 latin1,照样出问题。所以连接字符串、客户端配置、init_connect 都得同步到位,缺一不可。











