字符集与排序规则:utf8mb4与乱码问题、排序规则影响查询结果——经验分享/踩坑向
字符集应统一为utf8mb4并保证客户端、服务端、表字段一致,否则emoji乱码;排序规则影响查询、唯一索引和JOIN,需按业务语义选择并保持关联字段一致以避免隐式转换和结果异常。
字符集和排序规则这两件事,平时没人注意,一旦出问题就是“玄学”:明明存进去的中文,读出来变成问号;明明查的是 ABC,结果 abc 也匹配上了;更离谱的是,同一张表换个排序规则,唯一索引突然冲突。最近又踩了一轮,把经验整理一下,希望能帮你少加几个班。
从一次乱码排查说起
某次线上反馈:用户昵称里的 emoji 存不进去,接口直接报 Incorrect string value: '\xF0\x9F...'。第一反应是表字符集不对,一看建表语句:CHARSET=utf8。问题就出在这——MySQL 里的 utf8 并不是真正的 UTF-8,它最多只支持 3 字节,而 emoji、部分生僻字是 4 字节。utf8mb4 才是完整的 UTF-8 实现,所以现在新建库表,无脑选 utf8mb4 基本是标配。
但改成 utf8mb4 就万事大吉了吗?并没有。乱码问题往往是“链路”问题:客户端连接字符集、服务端默认字符集、表字符集、字段字符集,任何一环不一致都可能出幺蛾子。比如表已经是 utf8mb4,但连接串没加 characterEncoding=utf8,或者服务端 character_set_client 还是 latin1,写入时照样乱。排查时可以用 SHOW VARIABLES LIKE 'character_set%'; 和 SHOW VARIABLES LIKE 'collation%'; 看一眼,重点确认 character_set_client、character_set_connection、character_set_results 是不是 utf8mb4。连接层统一用 SET NAMES utf8mb4; 或 JDBC 的 useUnicode=true&characterEncoding=utf8,能省掉很多“为什么存进去是问号”的困惑。
排序规则不只是“大小写敏感”
字符集决定“能不能存”,排序规则决定“怎么比较”。很多人只记得 _ci 是大小写不敏感,_bin 是二进制比较,但实际影响面比想象中大。
常见排序规则:
utf8mb4_general_ci:老默认,比较快,但 Unicode 排序规则不够严谨;utf8mb4_unicode_ci:基于 Unicode Collation Algorithm,相对更准确,MySQL 5.7 常用;utf8mb4_0900_ai_ci:MySQL 8.0 默认,ai表示口音不敏感,ci表示大小写不敏感;utf8mb4_bin:按二进制比较,大小写、重音都敏感。
这些规则直接影响 WHERE、ORDER BY、GROUP BY、JOIN,甚至唯一索引。踩过最狠的一次:某业务用邀请码做唯一索引,字段排序规则是 utf8mb4_general_ci,结果用户输入 aBc 和 AbC 被判定为重复,插入失败。业务上邀请码本该区分大小写,这就是排序规则选错导致的“查询结果不符合预期”。反过来,如果邮箱唯一索引用 _bin,Test@xx.com 和 test@xx.com 就能同时存在,但大多数业务又希望它们视为同一个邮箱。所以选 ci 还是 bin,不是技术偏好,而是业务语义。
排序规则不一致引发的隐式转换
更隐蔽的坑是 JOIN。两张表关联字段的排序规则不同,比如一张是 utf8mb4_general_ci,另一张是 utf8mb4_unicode_ci,执行 JOIN 时可能直接报:
Illegal mix of collations (utf8mb4_general_ci,IMPLICIT) and (utf8mb4_unicode_ci,IMPLICIT) for operation '='
即使不报错,也可能因为隐式转换导致索引失效,查询从毫秒变秒级。解决办法要么统一排序规则,要么在 SQL 里显式 COLLATE,但后者容易让索引失效,最好还是从建表规范上统一。
另外,ORDER BY 也受排序规则影响。中文按 general_ci 排出来的顺序,和按拼音排完全不是一回事。如果业务要求中文按拼音排序,MySQL 层面并不好直接满足,通常得靠应用层或额外排序字段。
一些实用的避坑建议
- 新库新表统一
utf8mb4,MySQL 8.0 默认utf8mb4_0900_ai_ci,5.7 建议utf8mb4_unicode_ci。 - 连接层显式设置字符集,别依赖服务端默认值。
- 唯一索引、登录名、邀请码、订单号这类字段,先想清楚是否区分大小写,再决定用
_ci、_cs还是_bin。 - JOIN 字段的字符集和排序规则保持一致。
- 迁移时用
ALTER TABLE ... CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;,注意索引长度限制,必要时调整varchar长度或开启innodb_large_prefix。
字符集和排序规则就像数据库里的“地基”,平时看不见,塌了才后悔。记住一句话:字符集管存储,排序规则管比较;统一 utf8mb4 是底线,按业务选 collation 才是进阶。下次再遇到乱码或者“查询结果不对”,先别怀疑人生,查查这两个参数,大概率能找到答案。
转载请注明出处,版权归原作者所有。
星耀SVIP






