MySQL 里大小写不同的邮箱,为什么会撞上唯一索引?

MySQL 里大小写不同的邮箱,为什么会撞上唯一索引?

在 MySQL 8.0 中,如果邮箱列使用 utf8mb4_0900_ai_ci,Dev@example.com 和 dev@example.com 比较时会被视为相等;给这列加上唯一索引后,第二个值就可能报重复键。决定字符串比较方式的是列的排序规则(collation),不是 utf8mb4 这个字符集名称。

字符集和排序规则分别管什么

可以把两者分开理解:字符集规定文本如何编码和存储;排序规则规定字符串如何比较、排序和分组。MySQL 8.0 的服务器默认字符集和排序规则是 utf8mb4 与 utf8mb4_0900_ai_ci,但数据库、表、列都可以单独设置,所以不能只看服务器默认值就断定某一列的行为。

排序规则名称里的后缀也能提供线索:_ci 表示比较时不区分大小写,_cs 表示区分大小写;_ai 表示不区分重音,_as 表示区分重音。比如 utf8mb4_0900_ai_ci 同时不区分重音和大小写,utf8mb4_0900_as_cs 则两者都区分。

为什么唯一索引也认为它们重复

下面的表明确把邮箱列设为不区分大小写,并对它建立唯一索引:

sql 复制代码
CREATE TABLE account (
    id BIGINT PRIMARY KEY,
    email VARCHAR(255)
        CHARACTER SET utf8mb4
        COLLATE utf8mb4_0900_ai_ci NOT NULL,
    UNIQUE KEY uk_account_email (email)
);

插入 Dev@example.com 后,再插入 dev@example.com,会触发唯一键冲突。原因是唯一索引要保证键值彼此不同,而这一列的排序规则把两个邮箱比较为相等。换句话说,索引本身没有忽略大小写;它遵循列的比较规则。

先查列的实际排序规则

查看建表定义或列信息,不要凭经验猜:

sql 复制代码
SHOW FULL COLUMNS FROM account;

结果中的 Collation 列能显示邮箱字段当前使用的排序规则。也可以看完整定义:

sql 复制代码
SHOW CREATE TABLE account;

如果列定义没有显式写 COLLATE,它可能继承表、数据库等层级的默认设置。迁移旧项目时,不同表甚至同一表的不同列都可能不同。

怎样选才符合账号规则

先定产品规则:系统是否把大小写不同的邮箱视作同一个账号?写入、登录查询和唯一性约束都应遵循同一规则。

  • 大小写不同就应是同一账号:使用合适的大小写不敏感排序规则;应用端也应按同一规范处理输入。
  • 大小写不同允许是不同账号 :在 MySQL 8.0 中,可以将列改为大小写敏感的排序规则,例如 utf8mb4_0900_as_cs,并确认应用查询与唯一索引使用一致语义。
  • 准备调整排序规则或唯一约束:先按目标排序规则检查现有数据是否会合并成重复键,再执行变更,避免上线时才遇到索引创建失败。

例如,下面的查询可以按目标的大小写不敏感规则找出冲突组:

sql 复制代码
SELECT email COLLATE utf8mb4_0900_ai_ci AS email_key,
       COUNT(*) AS amount
FROM account
GROUP BY email COLLATE utf8mb4_0900_ai_ci
HAVING COUNT(*) > 1;

是否让邮箱区分大小写是业务决定,不要因为一次重复键报错就盲目切换排序规则。先确认账号如何判重,再同时核对字段排序规则、唯一索引和应用层的规范化逻辑。

**快速排查顺序:**查 SHOW CREATE TABLE → 确认列的 COLLATION → 明确账号判重规则 → 按目标规则检查历史数据 → 再调整列定义或索引。

参考:MySQL 8.0 字符集与排序规则、字符串比较的大小写行为、唯一索引。

相关推荐
专注仿真2 小时前
从「能跑通」到「能交付」:一套可直接落地的电商用户行为分析平台(Python + SQLite/MySQL + Streamlit 全栈源码与部署文档)
python·mysql·sqlite
1024奇点3 小时前
【仓颉语言入门 · 第二篇 第 10 课】
开发语言·数据库·ide·mysql·开源
catino4 小时前
分库分表详解
mysql
数据库小学妹4 小时前
MySQL表碎片与 OPTIMIZE TABLE:空间回收的代价与边界
数据库·后端·mysql
时间售卖铺5 小时前
MySQL 表的约束
运维·数据库·mysql·云原生
tongyiixiaohuang5 小时前
物料成本核算单同步返回信息策略实战教程:从金蝶云星空回写 MySQL 的闭环设计
数据库·mysql
深度学习04075 小时前
MySQL InnoDB Cluster 部署完整文档
android·mysql·adb
时间售卖铺6 小时前
MySQL 安装部署
运维·数据库·mysql·云原生
惊讶的猫8 小时前
mysql-多表连接查询(JOIN)
数据库·sql·mysql