MySQL字符集与排序规则全解析
这段文本是 MySQL 官方文档中关于“字符集(Character Set)和排序规则(Collation)”的详细说明,出自 MySQL 8.0 手册的第12章第3节。它系统地解释了 MySQL 如何在不同层级处理字符编码与排序规则。
下面我将用清晰、结构化的方式帮你理解这一大段内容,并提炼出核心要点,帮助你掌握其逻辑和实际应用。
🔍 一、整体结构概览
MySQL 的字符集与排序规则支持 四级默认机制(从高到低):
层级 | 默认来源 |
---|---|
1. 服务器(Server) | 启动参数或编译时设定 |
2. 数据库(Database) | 创建数据库时指定,否则继承服务器 |
3. 表(Table) | 创建表时指定,否则继承数据库 |
4. 列(Column) | 定义列时指定,否则继承表 |
✅ 原则:越靠近数据定义的地方优先级越高。
此外还有:
- 字符串字面量(Literal)
- 连接会话(Connection)
- 国家字符集(National Character Set)
📚 二、逐节解析与通俗理解
12.3.1 排序规则命名规范(Collation Naming Conventions)
排序规则名称是有规律的,格式如下:
字符集_语言_版本_敏感性后缀
常见后缀含义:
后缀 | 含义 |
---|---|
_ai | 不区分重音(accent-insensitive),如 é = e |
_as | 区分重音(accent-sensitive),如 é ≠ e |
_ci | 不区分大小写(case-insensitive),如 A = a |
_cs | 区分大小写(case-sensitive),如 A ≠ a |
_ks | 区分片假名/平假名(kana-sensitive,日语专用) |
_bin | 按二进制比较(区分大小写+按编码值排序) |
示例:
utf8mb4_0900_ai_ci
:utf8mb4 字符集,基于 Unicode 9.0 算法,不区分重音和大小写。latin1_swedish_ci
:latin1 字符集,瑞典语排序规则,不区分大小写。utf8mb4_bin
:utf8mb4 字符集,按二进制比较(区分大小写)。
⚠️ 注意:如果名字里没有
_ai
或_as
,则由_ci
或_cs
决定:
_ci
→ 隐含_ai
_cs
→ 隐含_as
12.3.2 服务器级字符集与排序规则(Server Level)
这是全局默认值。
设置方式:
mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_0900_ai_ci
如果不设置,默认就是 utf8mb4
和 utf8mb4_0900_ai_ci
(MySQL 8.0+)。
查看当前设置:
SHOW VARIABLES LIKE 'character_set_server';
SHOW VARIABLES LIKE 'collation_server';
✅ 作用:当创建数据库时未指定字符集,就使用这两个值作为默认。
12.3.3 数据库级字符集与排序规则(Database Level)
创建数据库时可以指定:
CREATE DATABASE mydbCHARACTER SET latin1COLLATE latin1_swedish_ci;
选择逻辑(按优先级):
- 显式指定
CHARACTER SET
和COLLATE
→ 使用 - 只指定字符集 → 使用该字符集的默认排序规则
- 只指定排序规则 → 自动使用该排序规则对应的字符集
- 都不指定 → 使用服务器的默认值
查看数据库字符集:
-- 方法1:切换数据库后查看
USE mydb;
SELECT @@character_set_database, @@collation_database;-- 方法2:直接查 information_schema
SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME = 'mydb';
💡 影响范围:
- 新建表的默认字符集
- LOAD DATA 读取文件时的编码
- 存储过程参数的默认字符集
12.3.4 表级字符集与排序规则(Table Level)
创建表时也可以指定:
CREATE TABLE t1 (name VARCHAR(50)
) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
选择逻辑:
- 显式指定 → 使用
- 只指定字符集 → 使用其默认排序规则
- 只指定排序规则 → 自动推导字符集
- 都不指定 → 继承数据库的设置
✅ 表字符集是 MySQL 扩展功能,标准 SQL 没有。
12.3.5 列级字符集与排序规则(Column Level)
这是最细粒度的控制,适用于 CHAR
, VARCHAR
, TEXT
, ENUM
, SET
类型。
CREATE TABLE users (username VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin,nickname VARCHAR(50) COLLATE utf8mb4_general_ci
);
选择逻辑:
- 显式指定 → 使用
- 只指定字符集 → 使用其默认排序规则
- 只指定排序规则 → 推导出对应字符集
- 都不指定 → 继承表的设置
✅ 这是标准 SQL 支持的功能。
⚠️ 修改列字符集可能造成数据丢失(如从 utf8mb4 改为 latin1)。
12.3.6 字符串字面量的字符集与排序规则(String Literals)
比如 'hello'
这样的字符串,在 SQL 中也有字符集和排序规则。
默认情况:
SELECT 'hello'; -- 使用连接会话的 character_set_connection 和 collation_connection
可以用“引介符”(Introducer)指定:
SELECT _latin1'hello'; -- 指定字符集为 latin1
SELECT _utf8mb4'你好' COLLATE utf8mb4_bin; -- 指定字符集+排序规则
🔔 引介符
_charset
只是“标记”,不会转换字符串本身!
重要提醒:转义字符 \n
, \t
等总是按 character_set_connection
解析!
例如:
SET NAMES latin1;
SELECT HEX(_sjis'à\n'); -- \n 被解释为换行(0A),即使用了 _sjis 引介符
因为 \n
是在解析阶段处理的,而引介符是在语义阶段起作用。
12.3.7 国家字符集(National Character Set)
SQL 标准中的 NCHAR
, NVARCHAR
, N'string'
表示“国家字符集”。
在 MySQL 中:
N'abc'
等价于_utf8'abc'
NCHAR(10)
等价于CHAR(10) CHARACTER SET utf8mb3
⚠️ 警告:
utf8mb3
已被弃用!未来会被utf8mb4
替代。
建议写成:
CHAR(10) CHARACTER SET utf8mb4
-- 或
N'abc' -- 但要注意未来兼容性
12.3.8 字符集引介符(Character Set Introducers)
就是前面说的 _charset
语法,可用于:
- 字符串:
_utf8'abc'
- 十六进制:
_latin1 X'4D7953514C'
- 位值:
_binary b'1000001'
关键点:
_binary
可以强制让十六进制/位值作为二进制字符串而非数字处理- 否则 MySQL 默认把
X'...'
当作数字
示例:
SET @v1 = X'000D' | X'0BC0'; -- 结果是 BIGINT 数字
SET @v2 = _binary X'000D' | X'0BC0'; -- 结果是 binary string
SELECT HEX(@v1), HEX(@v2); -- 输出不同(高位0是否保留)
12.3.9 实际例子分析(Examples)
例1:列覆盖表
CREATE TABLE t1 (c1 CHAR(10) CHARACTER SET latin1 COLLATE latin1_german1_ci
) DEFAULT CHARACTER SET latin2 COLLATE latin2_bin;
✅ 结果:c1 是 latin1
+ latin1_german1_ci
,不受表影响。
例2:列只指定字符集
CREATE TABLE t1 (c1 CHAR(10) CHARACTER SET latin1
) DEFAULT CHARACTER SET latin1 COLLATE latin1_danish_ci;
✅ 结果:c1 的排序规则是 latin1_swedish_ci
(latin1 的默认),不是 latin1_danish_ci
!
❗重点:列的默认排序规则来自字符集本身,而不是表!
例3:列完全依赖表
CREATE TABLE t1 (c1 CHAR(10)
) DEFAULT CHARACTER SET latin1 COLLATE latin1_danish_ci;
✅ 结果:c1 使用表的设置 → latin1
+ danish_ci
例4:层层继承
CREATE DATABASE d1 DEFAULT CHARACTER SET latin2 COLLATE latin2_czech_cs;
USE d1;
CREATE TABLE t1 (c1 CHAR(10));
✅ 结果:c1 使用数据库的设置 → latin2
+ czech_cs
🧠 总结:核心原则与最佳实践
项目 | 原则 |
---|---|
优先级顺序 | 列 > 表 > 数据库 > 服务器 > 连接 |
显式 > 隐式 | 越靠近数据定义的地方越优先 |
字符集与排序规则绑定 | 每个排序规则只属于一个字符集 |
引介符 _charset | 是“标记”不是“转换” |
转义字符解析 | 始终按 character_set_connection 解析 |
N’…’ 的风险 | 对应 utf8mb3 ,已弃用,建议避免 |
✅ 最佳实践建议
-
统一使用
utf8mb4
支持完整 Unicode(包括 emoji),避免乱码。 -
推荐排序规则:
- 通用:
utf8mb4_0900_ai_ci
(不区分大小写和重音) - 区分大小写:
utf8mb4_0900_cs_0900_as_cs
- 二进制比较:
utf8mb4_bin
- 通用:
-
建库时明确指定:
CREATE DATABASE app_dbCHARACTER SET utf8mb4COLLATE utf8mb4_0900_ai_ci;
-
建表时也建议指定(防止继承错误):
CREATE TABLE users (name VARCHAR(100) ) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-
关键字段明确指定(如用户名区分大小写):
username VARCHAR(50) COLLATE utf8mb4_bin
-
避免使用
N'...'
,改用_utf8mb4
显式标记:SELECT _utf8mb4'你好世界';
-
连接时设置正确字符集:
SET NAMES utf8mb4;
或在客户端连接时设置
charset=utf8mb4
。
📌 常用查询命令汇总
-- 查看服务器默认
SHOW VARIABLES LIKE 'character_set_server';
SHOW VARIABLES LIKE 'collation_server';-- 查看当前数据库默认
SELECT @@character_set_database, @@collation_database;-- 查看某个数据库的设置
SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'your_db';-- 查看支持的字符集和默认排序规则
SHOW CHARACTER SET;-- 查看某个字符集的所有排序规则
SHOW COLLATION WHERE Charset = 'utf8mb4';
如果你正在设计数据库或遇到乱码问题,可以根据这个层级模型一步步排查:
从客户端 → 连接 → 数据库 → 表 → 列 → 字符串字面量,确保每一层都一致或明确。
需要我根据你的具体场景(比如建表语句、乱码问题)进一步分析吗?