MySQL 不同字符集列的索引长度参数对比
这类问题通常出现在把旧表从 utf8mb3 迁移到 utf8mb4 之后:原来能创建的 INDEX(name(255)) 突然报索引过长。根因不是“255 这个参数失效”,而是 MySQL 对非二进制字符串把前缀参数按字符数解释,却按字节数检查索引上限。utf8mb4 最多使用 4 字节表示一个字符,所以同样的 255 个字符,最坏情况会占 1020 字节。
官方文档:https://dev.mysql.com/doc/refman/8.4/en/column-indexes.html
- 非二进制字符串的
INDEX(col(N))中,N按字符数写;索引前缀上限按字节数算。 - 保守换算公式是:安全字符数 = floor(字节上限 ÷ 字符集最大字节数)。
- 迁移前要同时看字符集、InnoDB 行格式、联合索引的总和与前缀选择性,不能只把 255 改成 191。
影响面:同一个 255 参数为什么在迁移后失败
我在排查这类迁移错误时,先把问题拆成两个单位:DDL 中的长度是字符,存储引擎限制是字节。MySQL 文档明确说明,CHAR、VARCHAR、TEXT 的索引前缀参数按字符解释;BINARY、VARBINARY、BLOB 则按字节解释。
因此旧表若使用 utf8mb3,255 个字符按最坏情况估算为 255 × 3 = 765 字节,可以贴近 767 字节上限。转换为 utf8mb4 后,最坏情况变为 255 × 4 = 1020 字节;在 COMPACT 或 REDUNDANT 行格式下就可能触发 Specified key was too long。

时间线:先按字符集换算,再对照两种常见上限
可以用下面这张保守对照表快速判断。它使用字符集的最大字节数,而不是某一批实际数据的平均字节数;这样迁移时不会因为当前样本 mostly 是 ASCII 而低估风险。
| 字符集 | 最大字节/字符 | 767 字节上限的保守前缀 | 3072 字节上限的保守前缀 |
|---|---|---|---|
| ascii / latin1 | 1 | 767 字符 | 3072 字符 |
| utf8mb3 | 3 | 255 字符 | 1024 字符 |
| utf8mb4 | 4 | 191 字符 | 768 字符 |
| utf16 | 最多 4 | 按 4 字节保守估算 191 字符 | 按 4 字节保守估算 768 字符 |
767 字节适用于 InnoDB 的 COMPACT 或 REDUNDANT 行格式;DYNAMIC 或 COMPRESSED 可使用到 3072 字节的前缀上限。这里的“安全前缀”是最坏字节数下的整数下取整,不代表前缀越长查询就一定越快。
-- 用表定义确认列字符集和行格式,再决定迁移参数。 SHOW CREATE TABLE customer; -- 查看索引是否已经是前缀索引,Sub_part 对字符串表示字符数。 SHOW INDEX FROM customer; -- 用最坏字节数做迁移前的保守估算。 -- utf8mb4 在 767 字节上限下:FLOOR(767 / 4) = 191。
触发条件:单列能算对,联合索引仍可能超限
迁移中第二个容易漏掉的点是联合索引。比如 (title(191), slug(191)) 的两个前缀都分别符合 utf8mb4 的 767 字节单列换算,但它们放在同一个索引键中时,必须按各 key part 的最坏字节数合计,再结合该存储引擎的总键长度限制判断。列字符集不同,也要分别使用各自的最大字节数。
另外,VARCHAR(255) 的列长度和 INDEX(col(191)) 的索引前缀不是同一个参数:前者决定列最多存多少字符,后者只把前 N 个字符放进索引。把列直接改成 VARCHAR(191) 会改变数据模型,只有确认业务不需要更长值时才这样做;仅为了降低索引大小,优先讨论索引前缀。

根因修复:缩短前缀、调整行格式,还是重新评估选择性
如果目标表确实是旧行格式,且业务只需要前缀查找,最小改动通常是把 utf8mb4 的前缀从 255 调整为 191,再单独评估唯一索引是否仍能满足唯一性。唯一索引不能因为超限而悄悄缩短,否则可能把原本不同的值压成相同的索引键。
如果表可以采用 DYNAMIC 或 COMPRESSED 行格式,则可以使用更大的 3072 字节预算,但这仍不是“所有索引都写 768”的理由:联合索引、实例页大小和列的实际业务区分度都需要重新核对。前缀太短会降低选择性,让 MySQL 在索引筛选后回表检查更多记录。
-- 仅示意旧表迁移;先在变更窗口确认行格式和索引用途。 ALTER TABLE customer MODIFY title VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL, DROP INDEX idx_title, ADD INDEX idx_title (title(191)); -- 调整后再次查看索引定义,确认前缀参数已经落在目标列上。 SHOW INDEX FROM customer WHERE Key_name = 'idx_title';
防复发:把“字符参数”与“字节预算”写进迁移清单
- 先读
SHOW CREATE TABLE,记录每个索引列的字符集、排序规则和 InnoDB 行格式。 - 按最大字节数计算,而不是拿现有数据样本的平均长度计算。
- 联合索引按所有 key part 的最坏情况汇总;涉及唯一索引时,先确认缩短前缀不会破坏唯一性。
- 前缀缩短后关注选择性;必要时改为更适合查询的列组合,而不是无条件放大索引。
常见问题
为什么 utf8mb4 常见的前缀长度是 191?
在 767 字节的旧 InnoDB 前缀上限下,按每字符最多 4 字节保守计算,floor(767 / 4) = 191。这不是 utf8mb4 的固定语法限制,而是字节上限换算结果。
实际数据大多是英文,可以按 1 字节计算吗?
不建议用于结构迁移。索引定义要能容纳列允许的最坏字符,实际值偏 ASCII 只能帮助理解平均占用,不能替代上限计算。
把行格式改成 DYNAMIC 后就不用管前缀了吗?
不用。它只把某些 InnoDB 表的前缀预算提高到 3072 字节,联合索引合计、页大小、唯一性和前缀选择性仍然要单独判断。
Redis XINFO STREAM 统计首尾消息与消费组状态
- 上一篇
- Redis XINFO STREAM 统计首尾消息与消费组状态
- 下一篇
- Redis HSTRLEN 怎样判断 Hash 字段值长度
-
- 数据库 · MySQL | 1小时前 |
- MySQL Performance Schema 按线程聚合等待事件
- 306浏览 收藏
-
- 数据库 · MySQL | 1小时前 |
- MySQL 事务隔离级别与锁定读的组合方案
- 271浏览 收藏
-
- 数据库 · MySQL | 1小时前 |
- MySQL 默认表达式与生成列的迁移清单
- 368浏览 收藏
-
- 数据库 · MySQL | 1小时前 |
- MySQL sys.schema_table_statistics_with_buffer 怎样定位表级 IO
- 335浏览 收藏
-
- 数据库 · MySQL | 1小时前 |
- MySQL INFORMATION_SCHEMA.TABLES 怎样区分表大小与索引大小
- 175浏览 收藏
-
- 数据库 · MySQL | 1小时前 |
- MySQL CHECK TABLE 怎样判断表结构与索引是否正常
- 374浏览 收藏
-
- 数据库 · MySQL | 2小时前 |
- MySQL 分区表的分区裁剪条件设计
- 154浏览 收藏
-
- 数据库 · MySQL | 2小时前 |
- MySQL LAG 与 LAST_VALUE 窗口帧的结果边界
- 432浏览 收藏
-
- 数据库 · MySQL | 2小时前 |
- MySQL 窗口函数共享排序的 WINDOW 子句写法
- 232浏览 收藏
-
- 数据库 · MySQL | 2小时前 |
- MySQL SHOW CREATE TABLE 和 INFORMATION_SCHEMA 为什么看到的属性不同
- 287浏览 收藏
-
- 数据库 · MySQL | 2小时前 |
- MySQL CHECKSUM TABLE 怎样比较两张表的数据摘要
- 233浏览 收藏
-
- 数据库 · MySQL | 2小时前 |
- MySQL 8.4 ANALYZE TABLE 直方图的桶数量配置方法
- 417浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 816次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 807次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 899次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 870次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 693次使用
-
- MySQL JSON_TABLE 展开数组时如何保留缺失字段
- 2026-09-10 501浏览
-
- MySQL 分区表怎么处理跨分区唯一键:分区列约束与建表取舍
- 2026-08-30 501浏览
-
- MySQL权限管理设置全攻略
- 2026-03-29 501浏览
-
- MySQL分片实现方法及常见方案解析
- 2025-06-24 501浏览
-
- MySQL表空间碎片怎么清理?超详细优化教程
- 2025-06-13 501浏览

