订阅更新

字符集和Collation在生产环境踩过什么坑?

MySQL手册 第 17 题 约 2 分钟读完

本文目录
  1. 先说结论
  2. 坑一:utf8不是真正的UTF-8
  3. 坑二:Collation不一致导致Join索引失效
  4. 坑三:出海业务的多语言排序问题
  5. 总结

先说结论

生产环境统一用utf8mb4字符集 + utf8mb4_unicode_ci排序规则。不要用utf8(它只支持3字节,不能存emoji)。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

字符集问题看起来很基础,但它能引发乱码、查询结果错误、索引失效等一系列问题。我在出海业务里被字符集坍过好几次。今天把常见的坑和最佳实践讲清楚。

坑一:utf8不是真正的UTF-8

MySQL的utf8只支持3字节字符,不能存储emoji和某些稀有汉字。4字节的字符会被截断或报错。

我在元宇宙社交App时,用户昵称里带emoji就会插入失败。检查后发现建表时用的是utf8而不是utf8mb4。改为utf8mb4后解决。

-- 检查当前字符集
SHOW CREATE TABLE users\G
 
-- 修改为utf8mb4
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

坑二:Collation不一致导致Join索引失效

这是最难发现的坑。如果两张表的Join字段的Collation不一样(比如一个是utf8mb4_general_ci,另一个是utf8mb4_unicode_ci),MySQL会做隐式转换,导致索引失效。

EXPLAIN会显示type=ALL(全表扫描),但你明明加了索引。这个问题我排查了半天才发现是Collation不一致。

解决方案: 统一所有表和字段的Collation。建表规范里必须明确指定。

坑三:出海业务的多语言排序问题

出海业务涉及多语言。utf8mb4_general_ci和utf8mb4_unicode_ci的排序规则不同:

general_ci: 简化版排序,快但不准确。比如德语的ß和ss不等价。

unicode_ci: 按Unicode标准排序,准确但稍慢。推荐出海业务使用。

MySQL 8.0还引入了utf8mb4_0900_ai_ci(基于Unicode 9.0),是8.0的默认Collation。

总结

统一用utf8mb4,统一Collation。建表规范里必须明确指定字符集和Collation。面试时能说清楚“utf8不是真正的UTF-8”和“Collation不一致导致索引失效”这两个坑,说明你是真正踩过的。

下一篇聊一个数据开发经常遇到的场景:MySQL的Buffer Pool怎么调优?内存分配有什么讲究?

你们被字符集坍过吗?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器