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

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

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

模拟信息如下

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信息

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.

命令行终端报错信息

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的差异导致的,版本升级的时候需要特别注意。

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失败。

参考文章

https://dev.mysql.com/doc/refman/8.0/en/innodb-row-format.html

https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_strict_mode

posted @ 2025-11-19 13:43  GreatSQL  阅读(0)  评论(0)    收藏  举报