字符集决定能存什么,排序规则决定怎么比、怎么排;字符集是编码规则,排序规则是比较逻辑的硬编码,二者必须在连接层、服务层、表层、列层全部对齐且显式配对。

字符集决定“能存什么”,排序规则决定“怎么比、怎么排”——这是最直接的区别。
字符集是编码规则,不是语言支持表
很多人误以为 utf8mb4 是“支持中文/emoji”的开关,其实它只是定义了“每个字符用几个字节、对应哪个 Unicode 码点”。比如:
-
utf8mb4允许存储 U+1F600(?)这类 4 字节 emoji,而utf8(即utf8mb3)会截断或报错 -
latin1根本没有中文的编码映射,存汉字会变成?或乱码,不是“显示问题”,是“根本没这个码位” - 即使设成
utf8mb4,如果客户端连接用的是latin1,照样存坏——字符集必须在连接层、服务层、表层、列层全部对齐
排序规则不是“排序选项”,而是比较逻辑的硬编码
utf8mb4_unicode_ci 和 utf8mb4_bin 都基于 utf8mb4 字符集,但行为完全不同:
-
_ci后缀:不区分大小写,'A' = 'a'成立;_cs或_bin下则不成立 -
_ai(如utf8mb4_0900_ai_ci):把é和e当作相同;_as则严格区分 -
_bin:完全按字节值比较,'a' (因为 <code>a的 ASCII 是 97,B是 66),这和自然语言习惯相反 - 同一个字段,
WHERE name = 'John'在_ci下能命中'john',在_bin下不能
改字符集不等于改排序规则,两者必须显式配对
执行 ALTER TABLE t CONVERT TO CHARACTER SET utf8mb4 时,MySQL 默认补上该字符集的默认排序规则(如 MySQL 8.0 是 utf8mb4_0900_ai_ci),但旧表可能继承的是 utf8mb4_general_ci。这种隐式补全容易导致:
- 索引失效:原
utf8mb4_general_ci索引在utf8mb4_0900_ai_ci下无法复用,查询变慢 - 去重异常:两个字符串在旧排序规则下相等,在新规则下不等,
GROUP BY结果突变 -
ALTER DATABASE db_name CHARACTER SET utf8mb4不会修改已有表的字符集,只影响后续新建表
真正麻烦的从来不是选哪个,而是所有层级(连接、库、表、列)是否一致、是否被隐式覆盖。一个 init-connect='SET NAMES latin1' 就能让整库 utf8mb4 形同虚设。











