更改“Mysql Row size too”的限制

我怎样才能改变这个限制

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

表:

 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 

这个问题也在serverfault上被问到。

你可能想看看这篇文章 ,它解释了很多关于MySQL行大小的内容。 需要注意的是,即使使用TEXT或BLOB字段,行大小仍可能超过8K(InnoDB的限制),因为它将每个字段的前768个字节存储在页面中。

解决这个问题的最简单方法是在InnoDB中使用Barracuda文件格式 。 这基本上通过只存储20字节指针而不是存储第一个768字节的文本数据来解决问题。


在OP中工作的方法是:

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

     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引擎的一个已知的(并经过validation的)错误 ,现在暂时的修正是作为临时存储回退到MyISAM引擎。 那么,在你的my.cnf文件中:

 internal_tmp_disk_storage_engine=MyISAM 

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

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

在我的情况下,有问题的blob表大概是16MB。 因此,我解决这个问题的方法是在my.cnf中添加一行,确保至less有10倍的数额,然后是一些:

innodb_log_file_size = 256M

如果您可以切换ENGINE并使用MyISAM而不是InnoDB,那应该有所帮助:

ENGINE=MyISAM

MyISAM有两个注意事项(可以说更多):

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

我想分享一个很棒的答案,这可能会有所帮助。 信贷比尔·卡尔文看到这里https://dba.stackexchange.com/questions/6598/innodb-create-table-error-row-size-too-large

它们因InnoDB文件格式而异。目前有两种格式叫Antelope和Barracuda。

中央表空间文件(ibdata1)始终处于Antelope格式。 如果使用file-per-table,则可以通过在my.cnf中设置innodb_file_format = Barracuda来使单个文件使用梭子鱼格式。

基本要点:

  1. 一个16KB的InnoDB数据页面必须至less包含两行数据。 另外每个页面都有一个包含页面校验和和日志序列号的页眉和页脚等等。 这就是你每行less于8KB的限制。

  2. 像INTEGER,DATE,FLOAT,CHAR这样的固定大小的数据types存储在这个主数据页面上,并计入行大小限制。

  3. 像VARCHAR,TEXT,BLOB这样的可变大小的数据types存储在溢出页面上,所以它们不能完全计算行的大小限制。 在Antelope中,除了存储在溢出页面之外,最多768字节的这样的列存储在主数据页面上。 梭子鱼支持dynamic行格式,所以它可能只在主数据页上存储一个20字节的指针。

  4. 可变大小的数据types也以1或更多字节为前缀来编码长度。 InnoDB行格式也有一个字段偏移量的数组。 所以有一个内部结构或多或lesslogging在他们的维基。

梭子鱼还支持ROW_FORMAT = COMPRESSED来获得溢出数据的进一步存储效率。

我也必须评论说,我从来没有见过一个精心devise的表超过了行大小的限制。 这是一个强大的“代码味道”,你违反了第一范式的重复组条件。

在my.cnf文件中设置以下内容并重新启动mysql服务器。

innodb_strict_mode = 0

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

 ALTER ${table} ROW_FORMAT=COMPRESSED; 

但是,我想你应该知道行存储 。
有两种列: 可变长度列 (如VARCHAR,VARBINARY,BLOB和TEXTtypes)和固定长度列 。 它们存储在不同types的页面中。

可变长度的列是这个规则的一个例外。 太长而不适合B树页面的BLOB和VARCHAR等列存储在称为溢出页面的单独分配的磁盘页面上。 我们把这些列称为离页的列。 这些列的值存储在单个溢出页面的链表中,每个这样的列都有自己的一个或多个溢出页面的列表。 在某些情况下,所有或长字段值的前缀都存储在B-树中,以避免浪费存储空间并消除读取单独页面的需要。

而当设置ROW_FORMAT的目​​的是

当使用ROW_FORMAT = DYNAMIC或ROW_FORMAT = COMPRESSED创build一个表时,InnoDB可以完全离页地存储长变长列值(对于VARCHAR,VARBINARY和BLOB和TEXTtypes),聚簇索引logging只包含一个20-字节指针溢出页面。

想了解更多关于DYNAMIC和COMPRESSED行格式

其他答案解决了问题。 我将解决根本原因:糟糕的模式devise。

不要在列上显示数组。 在这里你有3 * 10列应该被转换成10行3列在一个新的表(加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 

对于每个idTop中将有10个(或更less或更多?)行。

这消除了原来的问题,并清理架构。 (这不是“正常化”,正如在一些评论中所讨论的那样)。

不要切换到MyISAM; 它正在消失。
不要担心ROW_FORMAT

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