5.7到8.0版本升级导致备份导入失败:提示 "超过行长度"

5.7到8.0版本升级导致备份导入失败:提示 "超过行长度"

某应用开发商将用 mysqldump 从 MySQL5.7 导出的数据导入到GreatSQL时,某些表创建失败,提示超过行长度。

模拟信息如下

Java 复制代码
DROP TABLE cm_plat_user;
CREATE TABLE cm_plat_user
(id int NOT NULL AUTO_INCREMENT ,
netuserid varchar(255),
password varchar(255),
username varchar(255),
useaddress varchar(255),
mobilephone varchar(255),
telphone varchar(255) ,
email varchar(255) ,
sex   char(1) ,
user_type char(1),
description varchar(255),
userdespass varchar(255),
create_time datetime,
create_user varchar(255),
user_expire_time datetime,
passwd_expire_time datetime ,
login_flag char(1),
first_1ogintime datetime ,
last_logintime datetime DEFAULT NULL COMMENT '最后登录时间',
blocked_flag char(1),
blocked_reason  varchar(1000),
last_passwd_mod_time datetime,
user_status char(1),
home_url varchar(255),
theme varchar(255) ,
id_card_number varchar(255),
dept_name varchar(100),
admin_flag char(1) ,
area_code varchar(50) ,
PRIMARY KEY (id) ) ROW_FORMAT=COMPACT;

错误信息

error log信息

Shell 复制代码
2025-08-28T10:13:03.650086+08:00 34 [ERROR] [MY-011825] [InnoDB] Cannot add field blocked_reason in table demo.cm_plat_user because after adding it,
 the row size is 8761 which is greater than maximum allowed size (8126) for a record on index leaf page.

命令行终端报错信息

Bash 复制代码
ERROR 1118 (42000): Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.

问题分析

根据 error log 的日志信息表明,表 demo.cm_plat_user中添加字段 blocked_reason 后,行大小达到了 8761 字节,超过了 InnoDB 索引叶子页的最大允许大小 8126 字节。

问题反思

备份文件导入到GreatSQL时报错,导入MySQL 8.0.X会报错吗? 在MySQL 8.0.32(Server version: 8.0.32 MySQL Community Server - GPL)中进行测试,出现相同的报错信息。 MySQL 5.7升级到MySQL 8.0也有同样问题,说明该问题是MySQL 5.7和MySQL 8.0的差异导致的,版本升级的时候需要特别注意。

SQL 复制代码
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.32    |
+-----------+
1 row in set (0.00 sec)
mysql> CREATE TABLE cm_plat_user
    -> (id int NOT NULL AUTO_INCREMENT ,
    -> netuserid varchar(255),
    -> password varchar(255),
    -> username varchar(255),
    -> useaddress varchar(255),
    -> mobilephone varchar(255),
    -> telphone varchar(255) ,
    -> email varchar(255) ,
    -> sex   char(1) ,
    -> user_type char(1),
    -> description varchar(255),
    -> userdespass varchar(255),
    -> create_time datetime,
    -> create_user varchar(255),
    -> user_expire_time datetime,
    -> passwd_expire_time datetime ,
    -> login_flag char(1),
    -> first_1ogintime datetime ,
    -> last_logintime datetime DEFAULT NULL COMMENT '最后登录时间',
    -> blocked_flag char(1),
    -> blocked_reason  varchar(1000),
    -> last_passwd_mod_time datetime,
    -> user_status char(1),
    -> home_url varchar(255),
    -> theme varchar(255) ,
    -> id_card_number varchar(255),
    -> dept_name varchar(100),
    -> admin_flag char(1) ,
    -> area_code varchar(50) ,
    -> PRIMARY KEY (id) ) ROW_FORMAT=COMPACT;
ERROR 1118 (42000): Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.

解决方案

1、根据命令行的报错提示,修改表行格式为 DYNAMIC 或 COMPRESSED,系统参数innodb_default_row_format默认值为dynamic,建表是去掉ROW_FORMAT=COMPACT后,创建的表行格式默认为dynamic。

2、修改页大小: 将 innodb_page_size 设置为 32KB 或更大,重新初始化数据库。

3、关闭严格检查模式:设置innodb_strict_mode=OFF,然后创建表

风险提示:关闭 innodb_strict_mode 仅为 "临时规避创建报错",并非根本解决方案。此时表虽能创建,但后续执行 INSERT/UPDATE 操作时,若实际数据仍导致行长度超限,会直接触发数据写入失败(报错 "Row size too large"),甚至可能因数据截断导致数据完整性问题。

使用建议:该方案仅适合 "紧急验证数据结构"场景,生产环境优先选择方案 1(修改行格式)或方案 2(调整页大小),避免长期关闭严格模式。

行格式说明

DYNAMIC和COMPACT的差异:

DYNAMIC 行格式会将 BLOB/TEXT 等大字段完全存储在溢出页中,行内只保留 20 字节的指针,COMPACT会在行内保留768 字节前缀。

DYNAMIC 行格式提供与 COMPACT 行格式相同的存储特性,但增加了针对长可变长度列的增强存储功能,并支持大索引键前缀。 当用 ROW_FORMAT=DYNAMIC`` 创建表时,InnoDB可以完全在页外存储长可变长度的列值(对于VARCHAR, VARBINARY, BLOB和TEXT类型),集群索引记录只包含一个指向溢出页的20字节指针。大于或等于768字节的固定长度字段被编码为可变长度字段。

使用COMPACT行格式的表将可变长度列值(VARCHAR、VARBINARY、BLOB和TEXT类型)的前768字节存储在B-tree节点内的索引记录中,其余的存储在溢出页上。大于或等于768字节的固定长度列被编码为可变长度列,可以存储在页外。

COMPRESSED压缩行格式提供与DYNAMIC行格式相同的存储特性和功能,但增加了对表和索引数据压缩的支持。

对于页外存储,COMPRESSED行格式使用了与DYNAMIC行格式类似的内部细节,同时对表和索引数据进行了额外的存储和性能考虑,并使用了更小的页面大小。对于COMPRESSED行格式,KEY_BLOCK_SIZE选项控制在聚集索引中存储多少列数据,以及在溢出页上放置多少列数据。

innodb_strict_mode参数说明

innodb_strict_mode=ON时,InnoDB在检查无效或不兼容的表选项时返回错误而不是警告。

它检查KEY_BLOCK_SIZE、ROW_FORMAT、DATA DIRECTORY、TEMPORARY和TABLESPACE选项是否相互兼容以及是否与其他设置兼容。

innodb_strict_mode=ON还在创建或修改表时启用行大小检查,以防止由于所选页面大小的记录太大而导致INSERT或UPDATE失败。

参考文章

dev.mysql.com/doc/refman/...

dev.mysql.com/doc/refman/...

相关推荐
wuxuanok11 分钟前
Go——Swagger API文档访问500
开发语言·后端·golang
用户214118326360238 分钟前
白嫖Google Antigravity!Claude Opus 4.5免费用,告别token焦虑
后端
爬山算法1 小时前
Hibernate(15)Hibernate中如何定义一个实体的主键?
java·后端·hibernate
用户26851612107562 小时前
常见的 Git 分支命名策略和实践
后端
程序员小假2 小时前
我们来说一下 MySQL 的慢查询日志
java·后端
南囝coding2 小时前
《独立开发者精选工具》第 025 期
前端·后端
To Be Clean Coder3 小时前
【Spring源码】从源码倒看Spring用法(二)
java·后端·spring
想用offer打牌3 小时前
你真的懂Thread.currentThread().interrupt()吗?
java·后端·架构
程序员NEO4 小时前
LangChain4j 工具调用实战
后端