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

时间:2013-03-23 10:18:44

标签: mysql

如何更改限制

行大小太大(> 8126)。将某些列更改为TEXT或BLOB或使用ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED可能有所帮助。在当前行格式中,内联存储了{6}字节的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 

17 个答案:

答案 0 :(得分:101)

此问题也在serverfault上提出。

  

您可能需要查看this article,其中解释了很多   关于MySQL行大小。重要的是要注意即使你使用   TEXT或BLOB字段,您的行大小仍可能超过8K(限制为   InnoDB)因为它为每个内联字段存储了前768个字节   页面。

     

解决此问题的最简单方法是使用Barracuda file format   与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;
    

  3. 上述内容仍有可能无法解决您的问题。它是带有 InnoDB 引擎的known (and verified) bug,现在临时修复是作为临时存储回退到 MyISAM 引擎。所以,在my.cnf文件中:

    internal_tmp_disk_storage_engine=MyISAM
    

答案 1 :(得分:56)

我最近遇到了这个问题并以不同的方式解决了这个问题。如果您运行的是MySQL版本5.6.20,则系统中存在已知错误。见MySQL docs

  

重要   由于Bug#69477,对于大型外部存储的BLOB字段的重做日志写入可能会覆盖最多   最近的检查站。为解决这个问题,MySQL 5.6.20中引入的补丁限制了重做的大小   log BLOB写入重做日志文件大小的10%。由于此限制,innodb_log_file_size   应设置为大于您的行中找到的最大BLOB数据大小的10倍的值   表加上其他可变长度字段的长度(VARCHAR,VARBINARY和TEXT类型字段)。

在我的情况下,有问题的blob表大约是16MB。因此,我解决它的方法是在my.cnf上添加一行,确保我至少有10倍的数量,然后是一些:

innodb_log_file_size = 256M

答案 2 :(得分:22)

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

ENGINE=MyISAM

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

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

答案 3 :(得分:11)

我想分享一个很棒的答案,它可能会有所帮助。积分Bill Karwin在这里看到https://dba.stackexchange.com/questions/6598/innodb-create-table-error-row-size-too-large

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

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

基本要点:

  1. InnoDB数据的一个16KB页面必须至少包含两行数据。此外,每个页面都有一个页眉和一个包含页面校验和和日志序列号的页脚,依此类推。这就是你的每行限制小于8KB的地方。

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

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

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

  5. Barracuda还支持ROW_FORMAT = COMPRESSED以进一步提高溢出数据的存储效率。

    我还要评论说,我从未见过设计良好的表超过行大小限制。这是一种强烈的“代码味”,你违反了第一范式的重复群体条件。

答案 4 :(得分:10)

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

innodb_strict_mode = 0

答案 5 :(得分:5)

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

package remoting

import akka.actor.{ActorSystem, Props}
import com.typesafe.config.ConfigFactory

object Main extends App {
  val frontendConfig = ConfigFactory.load("frontend")

  val frontend = ActorSystem("frontend", frontendConfig)

  val frontendActor = frontend.actorOf(Props[FrontendActor], "FrontendActor")

  (1 to 20).foreach(i => frontendActor ! f"Msg #$i")

  frontendActor ! "stop"
}

答案 6 :(得分:2)

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

不要跨列显示数组。这里有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

每个Top id会有10行(或更少?或更多?)行。

这可以消除您的原始问题,并清除架构。 (这不是“正常化”,正如一些评论中所争论的那样。)

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

您需要更改代码才能执行JOIN并处理多行而不是多列。

答案 7 :(得分:2)

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

ALTER TABLE `my_table` ROW_FORMAT=DYNAMIC;

来自MYSQL Documentation

  

DYNAMIC行格式保持整个存储的效率   索引节点中的行(如果它适合)(与COMPACT和REDUNDANT一样)   格式),但这种新格式避免了填充B树的问题   具有大量长列数据字节的节点。动态   格式基于如果长数据值的一部分是的概念   存储在页外,通常最有效的存储所有   超值的价值。使用DYNAMIC格式时,可能会使用较短的列   保留在B树节点中,最小化溢出页面的数量   任何给定的行都需要。

答案 8 :(得分:1)

当我尝试从其他服务器恢复备份的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; (未包含在orignal sql备份文件中)

有助于我解决此问题的来源:MariaDB and InnoDB MySQL Row size too large

答案 9 :(得分: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

参考文献:

答案 10 :(得分:0)

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

ALTER ${table} ROW_FORMAT=COMPRESSED;

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

  

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

当设置ROW_FORMAT的目​​的是

  

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

想了解更多有关DYNAMIC and COMPRESSED Row Formats

的信息

答案 11 :(得分:0)

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

然后您有4个选择:

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

    internal_tmp_disk_storage_engine=MYISAM
    

重新启动mysql,查询正常。

答案 12 :(得分:0)

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

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

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

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

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

答案 13 :(得分:0)

我在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

答案 14 :(得分:0)

您需要对my.ini文件进行一些更改

在[mysqld]下添加它

innodb_strict_mode=0

更新这两行

innodb_log_file_size=256M
innodb_log_buffer_size=256M

innodb_strict_mode:启用该选项后,某些InnoDB警告将变为错误。

参考:https://mariadb.com/kb/en/innodb-strict-mode/

innodb_log_file_sizeinnodb_log_buffer_size的大小需要增加。

答案 15 :(得分:0)

当我销毁Laravel Homestead(Vagrant)盒子并重新开始时,我一直遇到这个问题。

  1. 从命令行homestead ssh

    进入SSH框
  2. 转到my.cnf文件sudo vi /etc/mysql/my.cnf

  3. 将以下行添加到文件底部(在!includedir下方)

    [mysqld]

    innodb_log_file_size=512M

    innodb_strict_mode=0

  4. 将更改保存到my.cnf,然后重新加载MYSQL sudo service mysql restart

答案 16 :(得分:0)

Mysql 5.6 上:

<块引用>

执行以下 SQL 命令:

Mysql > SET GLOBAL innodb_file_format=Barracuda; 
Mysql > ALTER TABLE `name_of_my_table_here` ENGINE=InnoDB ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=8;