MySQL 8.0 默认使用 utf8mb4 是为避免 emoji 等四字节字符插入失败,而非单纯追求先进;其变长编码特性使 ASCII 字符仍占 1 字节、汉字占 3 字节、仅 emoji 等占 4 字节,但会抬高存储、索引及排序开销。

MySQL 8.0 默认用 utf8mb4,不是为了“更先进”,而是为防 emoji 插入失败这类硬性报错;但它确实会悄悄抬高存储、内存和索引成本——尤其当你存的全是英文或数字时。
每个字符最多占 4 字节,但实际开销取决于内容
很多人误以为 utf8mb4 会让所有字段“自动变大 4 倍”。其实不是:utf8mb4 是变长编码,ASCII 字符(a-z、0-9、空格等)仍只占 1 字节,常见汉字占 3 字节,只有 emoji 或部分生僻字才占满 4 字节。
- 纯英文日志表用
utf8mb4存储,比latin1多占约 0–20% 空间(非 300%),但备份体积、主从同步流量、磁盘 I/O 都会线性上升 - 如果字段定义是
VARCHAR(500),InnoDB 实际分配的行格式空间按“最大可能字节数”预留(500 × 4 = 2000 字节),即使你只存英文,也会挤占更多页内空间,间接降低缓冲池利用率 -
SHOW TABLE STATUS中的Data_length看似正常,但innodb_buffer_pool_read_requests可能悄然升高——因为同样数据页能放的记录数变少了
索引前缀长度翻了 4 倍,但得手动满足前提条件
MySQL 8.0 把 InnoDB 单列索引上限从 767 字节放宽到 3072 字节,听起来很美。但这个能力不会自动生效:
- 必须确保表使用
ROW_FORMAT=DYNAMIC(SHOW CREATE TABLE t里要能看到),否则仍卡在 767 字节 - 即便满足,
VARCHAR(255)在utf8mb4下理论最大占 1020 字节(255×4),已超旧限制;想全字段建索引,得用VARCHAR(768)(3072 ÷ 4) - 如果没调好,
CREATE INDEX会静默截断成前缀索引(比如只索引前 191 字符),导致WHERE name LIKE 'xxx%'看似走索引,实则大量回表
排序规则升级带来隐性 CPU 开销
8.0 默认用 utf8mb4_0900_ai_ci,它基于 Unicode 9.0 的权重表做字符串比较,比老版 utf8mb4_unicode_ci 更准,但也更重:
- ORDER BY 中文字段时,
utf8mb4_0900_ai_ci会查完整 UCA 权重表,而utf8mb4_bin就是纯字节比,快 3–5 倍 - JOIN 多张表时,若一边用
utf8mb4_0900_ai_ci,另一边是utf8mb4_unicode_ci或utf8mb3,MySQL 会拒绝执行并报Illegal mix of collations - 临时表(如 GROUP BY + ORDER BY 混用)若涉及
utf8mb4_0900_ai_ci字段,更容易触发磁盘临时表(Created_tmp_disk_tables上升),因为内存临时表对字符集敏感度更高
真正容易被忽略的是:默认不等于安全。服务端设了 character_set_server = utf8mb4,只保新库新表;旧表字段的 CHARACTER SET 和 COLLATE 仍是迁移前的状态,连 SELECT @@collation_database 都可能骗人——得逐字段查 information_schema.COLUMNS 才算数。



















