# Mysql常见问题分析
# 一、表列数和行大小的限制
官方文档参考:https://dev.mysql.com/doc/refman/5.7/en/column-count-limit.html
# 问题1:Row size 大于 8126 字节
# 报错信息:
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 0 bytes is stored inline.
# 分析:
版本:Mysql5.7、mysql8.0
ROW_FORMAT: COMPACT
InnoDB将行大小(对于数据库页面内本地存储的数据)限制为略小于 4KB、8KB、16KB 和 32KB innodb_page_size 设置下的数据库页面的一半,以及略小于 64KB 页面下的 16KB。
mysql页大小可以通过sql:show variables like 'innodb_page_size';
检查,该参数需要在初始化数据库之前设置(默认16KB)
# 测试语句:
CREATE TABLE t4 (
c1 CHAR(255),c2 CHAR(255),c3 CHAR(255),
c4 CHAR(255),c5 CHAR(255),c6 CHAR(255),
c7 CHAR(255),c8 CHAR(255),c9 CHAR(255),
c10 CHAR(255),c11 CHAR(255),c12 CHAR(255),
c13 CHAR(255),c14 CHAR(255),c15 CHAR(255),
c16 CHAR(255),c17 CHAR(255),c18 CHAR(255),
c19 CHAR(255),c20 CHAR(255),c21 CHAR(255),
c22 CHAR(255),c23 CHAR(255),c24 CHAR(255),
c25 CHAR(255),c26 CHAR(255),c27 CHAR(255),
c28 CHAR(255),c29 CHAR(255),c30 CHAR(255),
c31 CHAR(255),c32 CHAR(255),c33 CHAR(255)
) ENGINE=InnoDB ROW_FORMAT=COMPACT DEFAULT CHARSET latin1;
# 解决方法:
修改行格式为 ROW_FORMAT=DYNAMIC 或 ROW_FORMAT=COMPRESSED
初始化数据库前:设置 innodb_page_size=32KB 或 innodb_page_size=64KB
修改字段类型为可变长度列类型(如varchar、text、blob、VARBINARY)
# 问题2:Row size 大于 65535 字节
# 报错信息:
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs.
# 分析:
MySQL 表的内部表示的最大行大小限制为 65535 字节,对于BLOB、TEXT列仅对行大小限制贡献 9 到 12 个字节,因为它们的内容与行的其余部分分开存储
# 测试语句:
CREATE TABLE t (a VARCHAR(10000), b VARCHAR(10000),
c VARCHAR(10000), d VARCHAR(10000), e VARCHAR(10000),
f VARCHAR(10000), g VARCHAR(6000)) ENGINE=InnoDB CHARACTER SET latin1;
# 解决方法:
减少字段数量、长度
使用text、blob字段类型
如果使用utf8mb4编码,可以尝试更换为utf8mb3
# 二、InnoDB 限制
官方文档参考:https://dev.mysql.com/doc/refman/5.7/en/innodb-limits.html
# 问题3:索引超长 767 字节
# 报错信息:
ERROR 1071: Specified key was too long; max key length is 767 bytes ERROR 1709 (HY000): Index column size too large. The maximum column size is 767 bytes.
# 分析:
版本:Mysql5.5、Mysql5.7 如果innodb_large_prefix启用(默认),则对于InnoDB使用 DYNAMIC 或 COMPRESSED 行格式的表,索引键前缀限制为 3072 字节。如果 innodb_large_prefix禁用,则对于任何行格式的表,索引键前缀限制为 767 字节
InnoDB对于使用 REDUNDANT 或 COMPACT 行格式的表, 索引键前缀长度限制为 767 字节。例如,假设使用 utf8mb3 字符集,并且每个字符最多占用 3 个字节,如果在 TEXT 或 VARCHAR 列上创建超过 255 个字符的列前缀索引,你可能会遇到这个限制。
另外:如果在创建 MySQL 实例时通过指定 innodb_page_size 选项将InnoDB 页面大小减小到 8KB 或 4KB ,则索引键的最大长度会根据 16KB 页面大小的 3072 字节限制按比例降低。也就是说,当页面大小为 8KB 时,索引键的最大长度为 1536 字节,当页面大小为 4KB 时,索引键的最大长度为 768 字节
# 解决方法:
- 开启 innodb_large_prefix=on (该配置高版本mysql8.0已弃用)
# 三、其他
# 问题4:Sql_mode报错
# 报错信息:
ERROR 1231 (42000) a line-xxx: Variable 'sql_mode' can't be set to the value of 'NO_AUTO_CREATE_USRR'.
# 分析:
sql_mode: NO_AUTO_CREATE_USRR 在高版本已经废弃
# 解决方法:
如果需要动态修改sql_mode, 可以使用以下语句来排除不支持的选项:
SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION';
SET SESSION sql_mode = 'STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION';