bigywater.tech
MySQL / InnoDB · 77

字符集与排序规则

同样的字符集、同样的数据,只改排序规则,看同一条查询和同一个唯一索引的真实行为会有多大差别。

3行 vs 1行
同一条查询在两种排序规则下真实命中的行数
唯一索引真实拒绝
大小写变体在ci排序规则下被当成同一个值

做的事:同样的数据,同样的字符集,只改排序规则

代码CREATE TABLE coll_ci (id INT PRIMARY KEY, name VARCHAR(50)) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; CREATE TABLE coll_bin (id INT PRIMARY KEY, name VARCHAR(50)) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin; -- 两张表真实都插入 'Alice','alice','ALICE','Bob'

验证:同一个查询,真实命中的行数不一样

实测 · 本机执行输出(都是 WHERE name='alice')
coll_ci(utf8mb4_0900_ai_ci,不区分大小写):
  id=1 Alice   id=2 alice   id=3 ALICE   ← 真实3行全命中

coll_bin(utf8mb4_bin,逐字节比较):
  id=2 alice   ← 真实只命中这一行

字符集(utf8mb4)决定的是"怎么把字符存成字节",两张表这部分真实完全一样;排序规则(collation)决定的是"怎么比较两个值是否相等、谁大谁小"——_ai_ci结尾的规则真实表示"accent insensitive, case insensitive"(不区分重音和大小写),_bin表示按字节精确比较。同一份数据、同一条查询语句,真实因为排序规则不同得到了完全不同的结果集。

验证:唯一索引真实把"不区分大小写"这件事变成了硬约束

实测 · 本机执行输出
ALTER TABLE coll_ci ADD UNIQUE INDEX uq_name (name);
→ ERROR 1062: Duplicate entry 'alice' for key 'coll_ci.uq_name'
   (表里当时还有Alice/alice/ALICE三行,真实被判定为重复)

删到只剩一行'Alice'之后,索引真实创建成功;
再插入 'alice':
→ ERROR 1062: Duplicate entry 'alice' for key 'coll_ci.uq_name'   ← 真实又报重复了
这两次真实的Duplicate entry报错,直接证明了排序规则不只是影响查询结果,还会真实影响唯一约束的判定——在utf8mb4_0900_ai_ci这个排序规则下,'Alice'、'alice'、'ALICE'被真实当成同一个值,唯一索引不允许它们同时存在。这个特性在用户名、邮箱这类"大小写不应该影响唯一性"的字段上真实是期望行为;但如果一个字段本来就需要区分大小写(比如某些编码、密码哈希的展示值),用错了排序规则会导致本该能同时存在的数据真实被拒绝插入。

分步演示:同一份数据,两种排序规则下的真实差异

每一步都是本文上面用真实查询和唯一索引测试跑出来的原始结果。

排序规则真实决定了什么叫'相同'
这一步新验证的行为

    本文用到的工具

    • 本机 MySQL 26.7.0(InnoDB),两张字符集相同、排序规则不同的表
    • utf8mb4_0900_ai_ci(不区分大小写) vs utf8mb4_bin(逐字节比较)
    京ICP备2026067502号-1京公网安备11010502063487号