alter table ... add index报“index column size too large”错误,根本原因是mysql 5.7默认compact格式+utf8mb4下单列索引前缀上限为767字节,而非字段定义长度;varchar(255)在utf8mb4中理论占1020字节,超限。

为什么ALTER TABLE ... ADD INDEX会报Index column size too large
根本不是字段本身“太大”,而是 MySQL 5.7 默认用 COMPACT 行格式 + utf8mb4 字符集时,单列索引前缀上限卡死在 767 字节。比如 VARCHAR(255) 在 utf8mb4 下理论占 1020 字节(255 × 4),一建索引就超限。错误信息里说的 “column size” 指的是索引键计算出的字节数,不是定义长度。
直接改字段长度是最稳的解法
多数情况下,没必要索引整个长字段——尤其像 JWT token、URL、JSON blob 这类内容,前缀已足够区分。
-
VARCHAR(255)改成VARCHAR(191):因为 191 × 4 = 764 ≤ 767,刚好踩线安全 - 如果业务允许更短,
VARCHAR(64)或VARCHAR(128)更好,索引体积小、查询快 - 别只改
CREATE TABLE语句,已有表必须用ALTER TABLE t MODIFY COLUMN c VARCHAR(191)同步调整 - 注意:修改字段长度可能触发表重建,大表要评估锁时间和磁盘空间
用前缀索引绕过字节限制
不改字段定义,只索引前 N 个字符,MySQL 允许你指定字节数(对 VARCHAR 是字符数)。
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
-
CREATE INDEX idx_token ON users(token(191))—— 显式声明前 191 字符 - 别写
token(255),哪怕字段是VARCHAR(255),MySQL 仍会按 255×4 算字节数并报错 - 前缀长度要结合数据分布选:用
SELECT COUNT(DISTINCT LEFT(token, 128)) / COUNT(*) FROM users看区分度,80% 以上就比较稳妥 - 前缀索引不能用于
ORDER BY或GROUP BY整字段场景,这点容易被忽略
配置调优只对新表生效,旧表还得手动改
设 innodb_large_prefix=ON 和 innodb_file_format=Barracuda 只是打开开关,不自动升级现有表结构。
- 动态设置后,新建表默认仍用
COMPACT格式,必须显式加ROW_FORMAT=DYNAMIC - 已有表得执行
ALTER TABLE t ROW_FORMAT=DYNAMIC才能享受 3072 字节上限 -
SET GLOBAL修改不持久,重启失效;要永久生效,必须写进my.cnf并重启 mysqld - 线上环境慎用:
Barracuda+DYNAMIC对备份/恢复工具兼容性有要求,不是所有运维流程都支持
真正麻烦的从来不是“怎么让索引建上去”,而是字段设计阶段没想清楚这个字段到底需不需要全文可查、是否真要索引全部内容。临时打补丁容易,但后续查不到、排序错、备份失败这些坑,往往在改配置那一刻就埋下了。










