124

如何更改限制

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

桌子:

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 
4

18 回答 18

130

这个问题也被问到了serverfault

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

解决这个问题的最简单方法是在 InnoDB中使用Barracuda 文件格式。这基本上通过仅存储指向文本数据的 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
于 2013-03-23T10:32:24.967 回答
65

我最近遇到了这个问题并以不同的方式解决了它。如果您正在运行 MySQL 5.6.20 版,则系统中存在已知错误。查看MySQL 文档

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

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

innodb_log_file_size = 256M

于 2014-08-30T02:54:36.250 回答
44

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

innodb_strict_mode=0
于 2017-06-03T12:01:18.977 回答
24

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

ENGINE=MyISAM

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

  1. 你不能使用事务。
  2. 您不能使用外键约束。
于 2015-05-29T19:18:03.773 回答
16

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

ALTER TABLE `my_table` ROW_FORMAT=DYNAMIC;

来自 MYSQL文档

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

于 2018-06-01T16:15:16.373 回答
13

我想分享一个很棒的答案,它可能会有所帮助。学分 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. 一页 16KB 的 InnoDB 数据必须至少包含两行数据。此外,每个页面都有一个页眉和一个页脚,其中包含页面校验和和日志序列号等。这就是您获得每行小于 8KB 的限制的地方。

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

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

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

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

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

于 2013-07-09T09:58:05.420 回答
7

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

USE db_name;
ALTER TABLE table_name ENGINE=MYISAM;
于 2018-04-10T13:13:30.300 回答
5

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 字节的字段太多,它将崩溃(超过 max row_size)。latin1 不常见,但如果开发人员不小心,则很有可能使用 utf-8。

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

在 my.cnf 中:

innodb_page_size=32K

参考:

于 2019-11-01T06:09:50.057 回答
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 备份文件中的表创建语句中:

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 and InnoDB MySQL Row size too large

于 2018-02-04T19:19:25.047 回答
3

您需要对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_size&innodb_log_buffer_size需要增加尺寸。

于 2020-11-23T12:17:14.853 回答
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. _

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

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

您将需要更改代码来JOIN处理多行而不是多列。

于 2017-10-12T16:15:15.070 回答
2

我在 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
于 2019-09-30T12:36:48.410 回答
2

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

  1. 从命令行 SSH 进入该框homestead 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,然后重新加载 MYSQLsudo service mysql restart

于 2020-12-03T03:04:35.033 回答
1

要解决此问题,您必须在 phpmyadmin 中将 innodb 更改为 myisam。看这张图片。

在此处输入图像描述

于 2021-09-13T13:24:38.873 回答
0

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

然后,您有 4 个选项:

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

    internal_tmp_disk_storage_engine=MYISAM
    

重启mysql,查询正常。

于 2019-07-10T08:39:04.053 回答
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; 
于 2021-05-20T19:03:32.070 回答
0

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

ALTER ${table} ROW_FORMAT=COMPRESSED;

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

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

当设置 ROW_FORMAT 的目的是

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

想了解更多关于动态和压缩行格式的信息

于 2017-06-14T09:01:05.517 回答
0

这是给感兴趣的人的简单提示:

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

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

以防万一,我在 /etc/mysql/mariadb.conf.d/50-server.cnf 中设置了 innodb_default_row_format = DYNAMIC (无论如何它都是默认的)

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

于 2019-09-28T08:42:40.380 回答