ERROR 1118 根本原因不是数据量大,而是InnoDB行内存储超8126字节硬限制;必须改ROW_FORMAT=DYNAMIC(需配套innodb_file_per_table=ON)或改字段为TEXT/BLOB,不可依赖调参或删数据。

直接结论:这不是数据量问题,而是单行所有字段加起来超出了 InnoDB 的 8126 字节硬限制。必须调整存储格式或字段类型,不能靠删数据或调大内存解决。
为什么会出现 ERROR 1118 (42000): Row size too large (> 8126)
InnoDB 默认使用 ROW_FORMAT=COMPACT(或 REDUNDANT),这种格式下,每个 VARCHAR、TEXT、BLOB 字段的前 768 字节会强制存进主记录页,其余部分才外链到溢出页。如果表里有很多长 VARCHAR(比如 VARCHAR(4000) × 3),光是这 768×3 就快 2300 字节了,再叠加上其他字段(时间戳、INT、索引指针、事务 ID、回滚指针等),很容易突破 8126。
常见触发场景:
- 用 SQLAlchemy 或 Django ORM 自动生成建表语句,把
err_solution设成VARCHAR(65532)—— 这在语法上合法,但实际建表时就卡住 - 从 MyISAM 转 InnoDB 时没改格式,原表字段宽泛但没暴露问题,一转就报错
- ALTER TABLE 增加多个长文本字段后执行失败
必须同时改三个配置才能生效
只改 ROW_FORMAT=DYNAMIC 是不够的,MySQL 会静默忽略它,除非底层支持格式已启用。需要三步一起做:
- 确认
innodb_file_format已设为Barracuda(MySQL 5.7+ 默认已弃用该参数,但旧版本仍需显式设置) - 开启
innodb_file_per_table = 1(否则无法为单表指定 ROW_FORMAT) - 执行
ALTER TABLE tbl_name ROW_FORMAT=DYNAMIC;或建表时直接指定
示例操作:
SET GLOBAL innodb_file_per_table = 1; -- MySQL 5.6 需要(5.7+ 可跳过) SET GLOBAL innodb_file_format = Barracuda; <p>ALTER TABLE amazon_errcode ROW_FORMAT=DYNAMIC;
注意:ROW_FORMAT=DYNAMIC 和 ROW_FORMAT=COMPRESSED 都能解决该问题,但后者压缩开销略高,一般选 DYNAMIC 即可。
VARCHAR 改 TEXT/BLOB 是更稳妥的长期方案
虽然 ROW_FORMAT=DYNAMIC 能绕过限制,但它只是让长字段完全外链(不存 768 字节前缀),对查询性能影响不大,但不如直接改类型来得干净。
推荐优先级:
- 字段只读或极少用于 WHERE/ORDER BY?→ 直接改成
TEXT或MEDIUMTEXT(TEXT最大 65535 字节,MEDIUMTEXT是 16MB) - 字段要建索引?→ 用
TEXT+ 指定前缀长度,例如INDEX(err_desc(255)) - 字段内容极长且结构化(如 JSON)?→ 改用
JSON类型(MySQL 5.7+),它自动按需外链,且支持函数索引
错误示范:VARCHAR(65532) —— 它既浪费空间,又容易触发 1074 错误(“Column length too big”),还无法被全文索引高效利用。
容易被忽略的关键点
很多团队改完 ROW_FORMAT 就以为万事大吉,但漏掉了两个实际运行中会出问题的地方:
-
mysqldump导出的 SQL 默认不含ROW_FORMAT子句,还原时若目标库没配好全局格式,会退回到 COMPACT,再次报错 - 某些同步工具(如 MySQL2ByteHouse_CDW)在全量拉取时会先建空表,如果建表语句没带
ROW_FORMAT,即使源表是 DYNAMIC,也会失败
所以,真正可靠的方案是:字段设计阶段就避免堆砌长 VARCHAR;补救时三步配置+改表+检查 dump 和同步链路是否继承格式。


















