mysql中varchar(255)在utf8mb4下建索引会超767字节限制,导致自动截断为191字符(764字节),引发索引失效;需统一数据库、表、列、连接及驱动的字符集与排序规则,并启用innodb_large_prefix等配置规避性能退化。

不是“默认改了就变慢”,而是 utf8mb4 改变了字段实际存储开销和索引行为,不调整配套配置时才会拖慢查询。
utf8mb4 让 VARCHAR 字段的索引长度超限
MySQL InnoDB 默认单列索引最大长度是 767 字节(innodb_large_prefix = OFF 时)。utf8mb4 下每个字符最多占 4 字节,所以 VARCHAR(255) 字段建索引会尝试占用 255 × 4 = 1020 字节 → 超限失败或自动截断为前 191 字符(191 × 4 = 764),导致索引失效。
- 现象:
ALTER TABLE t ADD INDEX idx_name(name)不报错但SHOW INDEX FROM t显示Sub_part = 191,而非NULL - 验证:执行
EXPLAIN SELECT * FROM t WHERE name = 'xxx',若key_len明显小于预期(比如只有 764),说明索引被截断 - 解法:启用
innodb_large_prefix = ON(需同时设innodb_file_format = Barracuda和innodb_file_per_table = ON),再重建表或索引
连接层与字段级字符集不一致触发隐式转换
即使 character_set_server = utf8mb4,若某张表的 name 列仍是 CHARSET=utf8(即 utf8mb3),而应用连接用 SET NAMES utf8mb4,MySQL 在比较时会把字段值从 utf8mb3 转成 utf8mb4 再比——这个转换无法走索引,且每次查询都发生。
- 典型错误现象:
WHERE name = ?在 utf8 列上变全表扫描,EXPLAIN中type = ALL,Extra出现Using where但无Using index - 检查方式:
SHOW CREATE TABLE t看列定义;SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'db_name' - 必须同步改:数据库、表、列、连接、应用驱动参数(如 JDBC 的
characterEncoding=utf8mb4)五处,缺一不可
排序规则变更影响 JOIN 和 GROUP BY 性能
MySQL 8.0 默认排序规则从 utf8mb4_general_ci 升级为 utf8mb4_0900_ai_ci。新规则更准确(支持 Unicode 9.0、大小写/重音不敏感),但字符串比较开销略高;若 JOIN 的两张表字段用不同 collation(比如一张是 _general_ci,一张是 _0900_ai_ci),MySQL 会强制转成同一 collation 再比,同样绕过索引。
- 查不一致:
SELECT TABLE_NAME, COLUMN_NAME, COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'db' AND DATA_TYPE IN ('varchar', 'char', 'text') - 统一建议:批量执行
ALTER TABLE t MODIFY COLUMN c VARCHAR(N) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci - 注意:修改 collation 不改变存储,但会影响
ORDER BY、DISTINCT、临时表排序等场景的 CPU 消耗
真正卡住性能的,从来不是 utf8mb4 本身,而是它暴露了过去被忽略的字符集链路断裂——字段没改、索引没重算、collation 混用、连接没对齐。这些地方一旦漏掉一个,查询就可能从毫秒级掉到秒级。











