必须统一使用utf8mb4字符集和utf8mb4_unicode_ci排序规则,配置需覆盖服务器、数据库、表、列及客户端连接各层级,且ALTER和JOIN操作中字符集与排序规则必须同时指定并严格一致,否则将导致隐式转换、索引失效或查询异常。

必须统一为 utf8mb4,且排序规则(COLLATION)也要一致;只改字符集不改排序规则,照样索引失效。
查清当前字段和连接实际用的字符集与排序规则
别靠猜,直接查。字段层和连接层不匹配是隐式转换的根源:
-
SHOW FULL COLUMNS FROM table_name LIKE 'column_name';—— 看Collation列,确认字段真实排序规则 -
SELECT @@character_set_client, @@character_set_connection, @@character_set_results;—— 查客户端连接三件套 -
SELECT @@collation_connection;—— 这个最关键,它决定 SQL 中字符串字面量按什么规则比较
常见陷阱:字段是 utf8mb4_unicode_ci,但 @@collation_connection 是 utf8mb4_0900_as_cs 或 latin1_swedish_ci,MySQL 会强制转换字段值再比对,索引直接跳过。
ALTER TABLE 时必须同时指定 CHARACTER SET 和 COLLATE
只写 CONVERT TO CHARACTER SET utf8mb4 不够——MySQL 会按 charset 默认 collation 覆盖,可能变成 utf8mb4_0900_ai_ci,而你原字段是 utf8mb4_unicode_ci,反而更不一致。
- 安全写法:
ALTER TABLE users MODIFY phone VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 批量修正前先备份,
MODIFY会锁表;若不能锁表,可用CHANGE配合 pt-online-schema-change - 注意:
utf8mb4_unicode_ci和utf8mb4_0900_ai_ci不兼容,不能混用;新项目建议统一用后者,老系统优先保持原有_unicode_ci以减少行为变更
应用连接串里必须显式声明 collation
JDBC、PDO、MyBatis 等默认不传 collation,MySQL 就 fallback 到 server 默认值,极易错配:
- JDBC:
jdbc:mysql://host/db?charset=utf8mb4&collation=utf8mb4_unicode_ci - PDO:
new PDO($dsn, $user, $pass, [PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"]) - 命令行客户端:
mysql --default-character-set=utf8mb4 --collation-server=utf8mb4_unicode_ci -u user -p
漏掉 collation=... 这部分,前面所有表和字段改得再整齐,查询时仍可能触发转换。
JOIN 场景下两边字段必须完全一致
两张表关联字段字符集或排序规则不同,哪怕都是 utf8mb4,只要 COLLATION 不同,MySQL 就无法直接走索引做 hash join 或 ref lookup:
- 检查关联字段:
SHOW FULL COLUMNS FROM t1 LIKE 'org_id';和SHOW FULL COLUMNS FROM t2 LIKE 'org_id'; - 修复原则:宁可改小表字段,也不要让 JOIN 条件做隐式转换;
ON t1.org_id = t2.org_id中任意一边被转,索引就废 - 临时绕过(仅限紧急):
ON t1.org_id = CONVERT(t2.org_id USING utf8mb4) COLLATE utf8mb4_unicode_ci,但性能差,不可长期用
真正稳的做法,是把所有参与 JOIN 的字符串字段,连字符集带排序规则,全部对齐到同一值;否则 EXPLAIN 里 type 一变 ALL,几十万行就卡死。


















