更改“ Mysql行大小太大”的限制


104

我如何更改限额

行大小太大(> 8126)。将某些列更改为TEXT或BLOB或使用ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED可能会有所帮助。在当前行格式中,BLOB内联存储768个字节的前缀。

表:

id  int(11) No       
name    text    No       
date    date    No       
time    time    No       
schedule    int(11) No       
category    int(11) No       
top_a   varchar(255)    No       
top_b   varchar(255)    No       
top_c   varchar(255)    No       
top_d   varchar(255)    No       
top_e   varchar(255)    No       
top_f   varchar(255)    No       
top_g   varchar(255)    No       
top_h   varchar(255)    No       
top_i   varchar(255)    No       
top_j   varchar(255)    No       
top_title_a varchar(255)    No       
top_title_b varchar(255)    No       
top_title_c varchar(255)    No       
top_title_d varchar(255)    No       
top_title_e varchar(255)    No       
top_title_f varchar(255)    No       
top_title_g varchar(255)    No       
top_title_h varchar(255)    No       
top_title_i varchar(255)    No       
top_title_j varchar(255)    No       
top_desc_a  text    No       
top_desc_b  text    No       
top_desc_c  text    No       
top_desc_d  text    No       
top_desc_e  text    No       
top_desc_f  text    No       
top_desc_g  text    No       
top_desc_h  text    No       
top_desc_i  text    No       
top_desc_j  text    No       
status  int(11) No       
admin_id    int(11) No 

1
是什么No显示?
hjpotter92 2013年

无法更新错误“行大小太大(> 8126)。将某些列更改为TEXT或BLOB或使用ROW_FORMAT = DYNAMIC或ROW_FORMAT = COMPRESSED可能会有所帮助。在当前行格式中,内联存储768字节的BLOB前缀。”
Lasha Kurt 2013年

您能否至少在评论中添加一些其他详细信息?
Eineki 2013年

1
如果此数据在另一个表中,请考虑使用外键代替,这将大大减少行大小并规范化数据库架构。
didierc

1
@AL:哎呀,你是对的-其他投一个接近的选票
pathikrit

Answers:


120

这个问题也已经在serverfault上被问到了。

您可能需要看一下这篇文章该文章对MySQL行大小进行了很多解释。重要的是要注意,即使您使用TEXT或BLOB字段,您的行大小仍可能超过8K(InnoDB的限制),因为它存储页面中内联的每个字段的前768个字节。

解决此问题的最简单方法是在 InnoDB中使用梭子鱼文件格式。通过仅存储指向文本数据的20字节指针而不是存储前768个字节,基本上可以完全解决该问题。


适用于OP的方法是:

  1. 将以下内容添加到该部分my.cnf下的文件中[mysqld]

    innodb_file_per_table=1
    innodb_file_format = Barracuda
  2. ALTER要使用的表ROW_FORMAT=COMPRESSED

    ALTER TABLE nombre_tabla
        ENGINE=InnoDB
        ROW_FORMAT=COMPRESSED 
        KEY_BLOCK_SIZE=8;

以上可能仍然无法解决您的问题。这是InnoDB引擎的一个已知(且已验证)错误,目前的临时解决方案是回退到MyISAM引擎作为临时存储。因此,在您的文件中:my.cnf

internal_tmp_disk_storage_engine=MyISAM

12
+1-> innodb_file_per_table部分至关重要,并且与将格式更改为梭子鱼密切相关。没有它,MySQL将默默地继续使用Antelope。
尼克

1
@Eduardo我建议先备份数据。但是,是的,您也可以在生产中执行此操作!
hjpotter92

3
使用innodb_file_per_table=1可激活此选项。
Stijn Geukens '16

2
这不能保证解决问题。请参阅此帖子以获取添加了这些设置但仍能够重现该错误的示例脚本。
塞林

1
@ user1183352更新了我上面的回复。感谢您再次提醒我进一步研究。:)
hjpotter92

61

我最近遇到了这个问题,并以另一种方式解决了这个问题。如果您正在运行MySQL版本5.6.20,则系统中存在一个已知错误。见MySQL文档

重要由于错误#69477,大型的,外部存储的BLOB字段的重做日志写操作可能会覆盖最新的检查点。为了解决此错误,MySQL 5.6.20中引入的补丁将重做日志的大小限制为BLOB写入的重做日志文件大小的10%。由于此限制,应将innodb_log_file_size的值设置为大于表行中找到的最大BLOB数据大小的10倍,再加上其他可变长度字段(VARCHAR,VARBINARY和TEXT类型字段)的长度。

在我的情况下,令人讨厌的Blob表大约为16MB。因此,我解决该问题的方法是在my.cnf中添加一行,以确保我至少有10倍于该金额,然后再添加一些:

innodb_log_file_size = 256M


发现。longblob一旦增加innodb_log_file_size参数,我在字段上的“行大小太大”错误就消失了。也正在运行5.6.20。
adamup 2014年

谢谢。正在运行自制软件5.6.21,更改参数解决了该问题。
nanoman 2014年

这和@ hjpotter92的答案都需要为我解决此错误。
塞林2015年

谢谢。正在运行5.6.21,此解决方案有所帮助。
petiar

这也没有解决我的问题。我正在考虑将我的许多VARCHAR字段替换为TEXT,就像我在类似线程上看到的那样。
PDoria

28

在my.cnf文件上设置以下内容,然后重新启动mysql服务器。

innodb_strict_mode=0

2
innodb_strict_mode=0->没有空格。否则,重新启动mariaDB 10.2会导致错误:-P
Pathros

我没有尝试使用mariadb,对于MySQL,它不需要删除空格。
卡尔

1
根据文档,禁用严格模式只能防止出现错误和警告,因此似乎无法解决问题! download.nust.na/pub6/mysql/doc/innodb-plugin/1.1/en/...
若昂·特谢拉

2
这似乎可行,让我创建没有问题的表并存储数据
Chris Muench

@João,它还有更多功能..dev.mysql.com/doc/refman/8.0/en/…
Karl

24

如果您可以切换引擎并使用MyISAM代替InnoDB,那应该会有所帮助:

ENGINE=MyISAM

MyISAM有两个警告(可能更多):

  1. 您不能使用交易。
  2. 您不能使用外键约束。

5
如果您不介意没有交易和外键约束,那就很好。但是请注意,切换到MyISAM时您会松开这些。
wobbily_col

这个建议是疯狂的-至少可以说这是警告!事务和前瞻性键约束是这种格式中最少的问题!
哈桑·赛义德

对不起,我拒绝了这个答案。请更新以提及所有涉及的警告。刚遵循此建议的任何人都将切换为我在任何生产系统上都不会使用的格式。
Remco Wendt

2
MyISAM即将消失。
里克·詹姆斯

2
为我工作。我的情况是我有300多个字段,每个字段的长度约为10。我在此表中没有任何关系,因此可以改用MyISAM。
罗伯特·塞勒

12

我想分享一个很棒的答案,可能会有所帮助。信用Bill Karwin参见此处/dba/6598/innodb-create-table-error-row-size-too-large

它们因InnoDB文件格式而异。目前有2种格式称为Antelope和Barracuda。

中央表空间文件(ibdata1)始终为羚羊格式。如果使用每表文件,则可以通过在my.cnf中设置innodb_file_format = Barracuda来使单个文件使用梭子鱼格式。

基本要点:

  1. 一页16KB的InnoDB数据必须至少包含两行数据。另外,每个页面都有一个页眉和页脚,其中包含页面校验和和日志序列号等。在那里,您的限制为每行少于8KB。

  2. 固定大小的数据类型(如INTEGER,DATE,FLOAT,CHAR)存储在此主数据页上,并计入行大小限制。

  3. 可变大小的数据类型(如VARCHAR,TEXT,BLOB)存储在溢出页面上,因此它们不会完全计入行大小限制。在Antelope中,此类列的多达768个字节除了存储在溢出页上之外,还存储在主数据页上。梭子鱼支持动态行格式,因此它只能在主数据页面上存储20字节的指针。

  4. 可变大小的数据类型还以1或更多字节为前缀来编码长度。InnoDB行格式还具有字段偏移量数组。因此,他们的Wiki中或多或少都记录着一个内部结构。

梭子鱼还支持ROW_FORMAT = COMPRESSED来提高溢出数据的存储效率。

我还必须评论说,我从未见过精心设计的表超过行大小限制。这是一种强烈的“代码气味”,您违反了“第一范式”的重复组条件。


7

我有同样的问题,这为我解决了:

ALTER TABLE `my_table` ROW_FORMAT=DYNAMIC;

从MYSQL 文档

如果适合,DYNAMIC行格式可以保持将整个行存储在索引节点中的效率(COMPACT和REDUNDANT格式也是如此),但是这种新格式避免了用大量数据字节填充B树节点的问题。长列。DYNAMIC格式基于以下思想:如果将长数据值的一部分存储在页外,则通常最有效地存储所有值在页外。对于DYNAMIC格式,较短的列可能会保留在B树节点中,从而最大程度地减少了任何给定行所需的溢出页数。


...但是您需要使用其他文件格式,所以您已经在梭子鱼上了吗?因为我在尝试该命令时遇到错误,说Warnings from last query: InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope
Ted

当我让HeidiSQL通过其内置的GUI运行相同的命令时,它以某种方式成功了,但是它根本没有帮助,我得到了相同的错误,Row size too large (>8126)
Ted

尝试在my.ini中设置innodb_file_format = Barracuda,然后尝试ALTER TABLE my_tableROW_FORMAT = DYNAMIC; 再次
多媒体

是的,我认为那实际上是我最终所做的,并且我认为可以解决。但我同时在绝望=)Thx中同时将许多列更改为TEXT,但实际上我认为就是这样。
Ted

好!如果您认为这是一个很好的答案,请对其进行投票并接受有效答复,谢谢!
多媒体

5

花了几个小时后,我找到了解决方案:只需在您的MySQL管理员中运行以下SQL,即可将表转换为MyISAM:

USE db_name;
ALTER TABLE table_name ENGINE=MYISAM;

如果问题在create table语句中发生,则无济于事。
马克·弗雷泽

create table具有相同的选项:CREATE TABLE ... ENGINE=MyISAM ...
xebeche

3

当我尝试从其他服务器还原备份的mysql数据库时遇到了这个问题。为我解决了此问题的方法是将某些设置添加到my.conf中(如上述问题),并另外更改了sql备份文件:

步骤1: 在my.conf中添加或编辑以下几行:

innodb_page_size=32K
innodb_file_format=Barracuda
innodb_file_per_table=1

步骤2将ROW_FORMAT = DYNAMIC添加到导致该错误的表的sql备份文件中的表create语句中:

DROP TABLE IF EXISTS `problematic_table`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `problematic_table` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
  ...
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 ROW_FORMAT=DYNAMIC;

上面的重要更改是ROW_FORMAT = DYNAMIC; (未包含在原始sql备份文件中)

帮助我解决此问题的源:MariaDB和InnoDB MySQL行大小太大


1
步骤1中描述的行不应有任何空格。行innodb_page_size=32K不起作用,因为在我的情况下,它导致重新启动MariaDB 10.2时出错。相反,我说innodb_strict_mode=0行,描述在这里
巴忒罗

1
感谢您对Pathros的反馈,我更新了答案并删除了step1中的空格。
matyas

对于MySQL <= 5.7.5的注释:innodb_page_size的32K无效选项。请参阅:dev.mysql.com/doc/refman/5.6/en/...
配音纳扎尔

另外,由于更改innodb_page_size需要重新创建,因此必须重新创建整个mysql服务器以进行修改ibdata*,这是破坏性的操作。观看您的系统日志以获取更多信息
Matija Nalis

2

其他答案解决了提出的问题。我将解决根本原因:不良的架构设计。

不要跨列展开数组。在这里,您有3 * 10列,应将它们转换为新表中3列的10行(加id号等)

您的Main桌子只有

id  int(11) No       
name    text    No       
date    date    No       
time    time    No       
schedule    int(11) No       
category    int(11) No       
status  int(11) No       
admin_id    int(11) No 

您的额外表格(Top)将有

id  int(11) No          -- for joining to Main
seq TINYINT UNSIGNED    -- containing 1..10
img   varchar(255)    No       
title varchar(255)    No       
desc  text    No    
PRIMARY KEY(id, seq)    -- so you can easily find the 10 top_titles

将有10(或更少?或更多?)中的行Top的每个id

这消除了您的原始问题,并清理了架构。(这不是某些评论中所讨论的“规范化”。)

难道转的MyISAM; 它正在消失。
不用担心ROW_FORMAT

您将需要更改代码以执行JOIN和处理多个行而不是多个列。


1

我在AWS RDS上使用MySQL 5.6。我在参数组中更新了以下内容。

innodb_file_per_table=1
innodb_file_format = Barracuda

我必须重新启动数据库实例才能使参数组更改生效。

另外,不支持ROW_FORMAT = COMPRESSED。我按以下方式使用DYNAMIC,并且效果很好。

ALTER TABLE nombre_tabla ENGINE=InnoDB ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=8

1

InnoDB表的最大行大小适用于数据库页面中本地存储的数据,对于4KB,8KB,16KB和32KB ,此表的最大行大小略小于一半

对于16kb页面(默认),我们可以计算:

Slightly less than half a page 8126 / Number of bytes to threshold for overflow 767 = 10.59 fields of 767 bytes maximum

基本上,您可以使用以下命令最大化一行:

  • 11个varchar字段> 767个字符(latin1 = 1个字节/字符)或
  • 11个varchar字段> 255个字符(mysql上的utf-8 =每个字符3个字节)。

请记住,如果字段> 767字节,它将仅溢出到溢出页面。如果767个字节的字段过多,它将崩溃(超过最大row_size)。如果开发人员不小心,latin1并不常见,但是utf-8很有可能。

对于这种情况,我认为您可能会将innodb_page_size增大到32kb。

在my.cnf中:

innodb_page_size=32K

参考文献:


0

我也遇到了同样的问题。我通过执行以下sql解决了这个问题:

ALTER ${table} ROW_FORMAT=COMPRESSED;

但是,我认为您应该了解行存储
有两种列:可变长度列(例如VARCHAR,VARBINARY以及BLOB和TEXT类型)和固定长度列。它们存储在不同类型的页面中。

可变长度列是该规则的例外。诸如BLOB和VARCHAR之类的列太长而无法容纳在B树页面上的列存储在单独分配的磁盘页面上,这些磁盘页面称为溢出页面。我们称此类列为页外列。这些列的值存储在溢出页面的单链接列表中,每个这样的列都有其自己的一个或多个溢出页面的列表。在某些情况下,长列值的全部或前缀都存储在B树中,以避免浪费存储空间并消除读取单独页面的需要。

并且当设置ROW_FORMAT的目​​的是

当使用ROW_FORMAT = DYNAMIC或ROW_FORMAT = COMPRESSED创建表时,InnoDB可以完全在页外存储长可变长度列值(对于VARCHAR,VARBINARY,BLOB和TEXT类型),而聚集索引记录仅包含20个指向溢出页面的字节指针。

想更多地了解动态和压缩行格式


0

如果这种情况发生在具有许多列的SELECT上,则可能是mysql正在创建一个临时表。如果此表太大而无法容纳在内存中,它将使用其默认的临时表格式(即InnoDB)将其存储在磁盘上。在这种情况下,适用InnoDB大小限制。

然后,您有4个选择:

  1. 像另一篇文章中所述更改innodb行大小限制,这需要重新初始化服务器。
  2. 更改您的查询以包括更少的列或避免导致其创建临时表(例如,删除order by和limit子句)。
  3. max_heap_table_size更改为较大,以便结果适合内存且无需写入磁盘。
  4. 将默认的临时表格式更改为MYISAM,这就是我所做的。更改my.cnf:

    internal_tmp_disk_storage_engine=MYISAM

重新启动mysql,查询正常。


0

这是任何有兴趣的人的简单提示:

使用10.3.17-MariaDB从Debian 9升级到Debian 10之后,我从Joomla数据库中出现一些错误:

[警告] InnoDB:无法field在table中添加字段databasetable因为添加后,行大小为8742,它大于索引叶页上记录的最大允许大小(8126)。

以防万一,我在/etc/mysql/mariadb.conf.d/50-server.cnf中设置了innodb_default_row_format = DYNAMIC(仍然是默认设置)

然后,我使用phpmyadmin为Joomla数据库中的所有表运行“优化表”。我认为由phpmyadmin完成的表重新创建在此过程中有所帮助。如果您碰巧安装了phpmyadmin,只需单击几下。


如果您是Joomla用户,请加入Joomla Stack Exchange,我们可以随时使用新的贡献者。
mickmackusa
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.