MySQL 中的 utf8 vs utf8mb4 区别

目录

核心区别

utf8在MySQL中是一个"不完整"的UTF-8实现 ,而utf8mb4才是真正的UTF-8实现

详细对比

1. 编码范围不同

字符集 最大字节数 支持的Unicode范围 备注
utf8 3字节 BMP平面(U+0000 ~ U+FFFF) 不支持4字节字符
utf8mb4 4字节 所有Unicode字符(包括Supplementary Planes) 完整UTF-8支持

2. 历史背景

  • utf8 (utf8mb3) : MySQL早期实现的"阉割版"UTF-8
    • 2003年引入,当时认为3字节足够表示所有字符
    • 实际是UTF-8的一个子集,后来更名为utf8mb3
  • utf8mb4 : MySQL 5.5.3引入
    • 完整的UTF-8实现
    • "mb4" = "multi-byte 4"

3. 实际影响最明显的场景

sql 复制代码
-- 这些字符在utf8下会出错,在utf8mb4下正常
-- 表情符号(Emoji)
INSERT INTO users (name) VALUES ('小明😊开心');  -- 需要utf8mb4

-- 部分生僻汉字
INSERT INTO text (content) VALUES ('𠀀𪚥𪚨');  -- 需要utf8mb4

-- 某些数学符号、音乐符号等
INSERT INTO symbols (symbol) VALUES ('𝄞𝄢');  -- 需要utf8mb4

4. 存储空间差异

sql 复制代码
-- 创建表对比
CREATE TABLE test_utf8 (
    id INT,
    text VARCHAR(100) CHARACTER SET utf8  -- 最大300字节
);

CREATE TABLE test_utf8mb4 (
    id INT,
    text VARCHAR(100) CHARACTER SET utf8mb4  -- 最大400字节
);

-- 注意:VARCHAR(100)对于utf8最多存储100个字符(但可能占用最多300字节)
-- 对于utf8mb4最多存储100个字符(但可能占用最多400字节)

5. 性能差异

方面 utf8 utf8mb4 说明
存储空间 较小 较大 utf8mb4可能多用约33%空间
索引长度 较短 较长 索引长度限制以字节为单位
排序性能 稍快 稍慢 差异通常不明显

关键限制

索引长度限制

sql 复制代码
-- utf8: 最大索引长度 767字节
-- utf8mb4: 最大索引长度 3072字节(MySQL 5.7+)

-- 但在早期版本中,InnoDB对utf8mb4的索引限制:
-- utf8: VARCHAR(255) 可以建索引 (255×3=765 < 767)
-- utf8mb4: VARCHAR(255) 不能建索引 (255×4=1020 > 767)
-- 需要改为 VARCHAR(191) (191×4=764 < 767)

-- 解决办法:修改innodb_large_prefix设置
SET GLOBAL innodb_large_prefix = ON;
SET GLOBAL innodb_file_format = Barracuda;

实际使用建议

1. 新项目一律使用utf8mb4

sql 复制代码
-- 数据库级别
CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 表级别
CREATE TABLE mytable (
    id INT PRIMARY KEY,
    content TEXT
) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 列级别
ALTER TABLE mytable MODIFY content VARCHAR(255) 
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

2. 现有系统迁移步骤

sql 复制代码
-- 1. 备份数据
-- 2. 修改数据库默认字符集
ALTER DATABASE database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 3. 修改表字符集
ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 4. 修改连接配置
-- 在my.cnf中:
[client]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4

[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

-- 5. 验证修改
SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';

3. 连接配置

bash 复制代码
# 命令行连接
mysql -u root -p --default-character-set=utf8mb4

# 应用程序连接示例
# Python (PyMySQL)
conn = pymysql.connect(charset='utf8mb4')

# PHP (PDO)
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8mb4', $user, $pass);

# Java (JDBC)
jdbc:mysql://localhost:3306/db?characterEncoding=utf8mb4

4. 排序规则选择

sql 复制代码
-- 常用排序规则
utf8mb4_unicode_ci      -- 基于Unicode标准排序,支持多语言(推荐)
utf8mb4_general_ci      -- 旧的排序规则,性能稍好但准确性较差
utf8mb4_bin             -- 二进制排序,区分大小写和重音
utf8mb4_0900_ai_ci      -- MySQL 8.0默认,基于Unicode 9.0标准

-- 查看所有utf8mb4排序规则
SHOW COLLATION LIKE 'utf8mb4%';

兼容性考虑

向下兼容性

  • utf8mb4完全兼容utf8(utf8mb3)存储的数据
  • 反向不兼容:utf8mb4的数据可能无法在utf8中正常显示

客户端兼容性

  • 所有现代客户端都支持utf8mb4
  • 确保客户端连接时也使用utf8mb4字符集

验证当前设置

sql 复制代码
-- 查看数据库、表、列的字符集
SELECT 
    TABLE_SCHEMA,
    TABLE_NAME,
    COLUMN_NAME,
    CHARACTER_SET_NAME,
    COLLATION_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'your_database'
  AND CHARACTER_SET_NAME IS NOT NULL;

-- 查看当前连接的字符集
SHOW VARIABLES WHERE Variable_name LIKE 'character_set_%' OR Variable_name LIKE 'collation%';

总结建议

  1. 始终使用utf8mb4,不要使用utf8
  2. 排序规则使用utf8mb4_unicode_ci(或MySQL 8.0的utf8mb4_0900_ai_ci)
  3. 注意索引长度限制,必要时调整字段长度
  4. 确保应用程序连接字符串也使用utf8mb4
  5. MySQL 8.0已将utf8mb4作为默认字符集
sql 复制代码
-- MySQL 8.0默认设置
mysql> SELECT @@character_set_database, @@collation_database;
+--------------------------+------------------------+
| @@character_set_database | @@collation_database   |
+--------------------------+------------------------+
| utf8mb4                  | utf8mb4_0900_ai_ci     |
+--------------------------+------------------------+

重要提示 :MySQL未来版本中,utf8可能会被重新定义为真正的UTF-8(目前utf8utf8mb3的别名),建议明确使用utf8mb4以避免不确定性。

相关推荐
数据知道2 小时前
PostgreSQL 实战:索引的设计原则详解
数据库·postgresql
强子感冒了2 小时前
MySQL学习随笔:数据类型与字段约束
学习·mysql
一只酸奶牛^_^2 小时前
解决LinuxDeploy部署mysql、redis数据库无法启动问题。
redis·mysql
老毛肚2 小时前
Spring 6.0基于JDB手写定制自己的ROM框架
java·数据库·spring
CodeBlossom2 小时前
MySQL进阶 索引
数据库·mysql
未来之窗软件服务2 小时前
数据库优化提速(四)数据库数据批量补齐—仙盟创梦IDE
数据库·数据库调优·仙盟创梦ide·东方仙盟
optimistic_chen3 小时前
【Redis系列】分布式锁
linux·数据库·redis·分布式·缓存
xuekai200809013 小时前
GaussDB-SQL优化案例
数据库·sql·gaussdb
老邓计算机毕设3 小时前
SSM养老院管理系统的设计于实现78fyn(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·计算机毕业设计·养老院管理系统·ssm 框架