【问题标题】:MariaDB 10.2 "Mysql Row size too large”, solution for existing large DB (terabytes)MariaDB 10.2“Mysql Row size too large”,现有大型数据库(TB)的解决方案
【发布时间】:2022-01-04 13:11:12
【问题描述】:

我想将数据库从 Maria10.1 升级到 Maria10.2,当我运行迁移时,在创建一些表时出现“Mysql Row size too large”错误。

抛出此错误的一个表有 40 个字段定义为:

varchar(250) DEFAULT NULL

表格本身是:

ENGINE=InnoDB DEFAULT CHARSET=latin1

我想我理解核心问题; innodb 将尝试存储大小

我有 2 个我发现可行的解决方案:

  1. 将列定义更改为将存储“页外”TEXT、BLOB 或 VARCHAR 大小 > 255 的类型(或大小),这允许将每一列作为 20 字节引用存储在行中,而不是存储列完全在行内。
  2. 设置 innodb_page_size=64k

这对于新数据库来说很好,但是我有现有的数据库需要升级,因为它们在不再受支持的 MariaDB 10.1 上运行。这些现有的数据库很大,应用这些解决方案很困难;对于解决方案 2,备份和导入 TB 的数据是“有风险的”且不容易,对于解决方案 1,可能需要考虑性能;可能是较慢的查询和增加的磁盘空间需求?

我的问题:

  • 首先;是否有可用于大型已建立数据库的替代解决方案,以提供更轻松的升级路径?
  • 其次;我可能不得不采用解决方案 1,如果这样做,我该如何减轻性能/存储影响/是否会对性能/存储产生重大影响?

其他一些相关信息:

[edit] 我知道规范化,但由于数据量大,这并不是一个真正的选择。

所有表都是innodb

关闭 innodb_strict_mode 不是一种选择

非常感谢您的观看!

【问题讨论】:

  • 与外观相反,解决方案 1 可能更理想。如果您使用的是varchar,则该行标记为` variable-length. So, if you are using TINYTEXT, the allowance is identical to varchar(
  • MariaDB 中的 InnoDB 声称支持长达 64KiB 的行。可以将表从 MyISAM 转换为 InnoDB,同时保留表的 ROW_FORMAT=COMPACT 特征。但是dynamic 行格式更强大。尝试做ALTER TABLE mytable ENGINE=InnoDB ROW_FORMAT=DYNAMIC,看看你是否得到了一张可行的桌子。您还可以考虑压缩行格式。这是一条评论,因为我不确定这是不是正确的答案。
  • 而且,由于每行中有那么多文本列,您可能需要研究数据库规范化,将文本列拆分到自己的表中。特别是如果任何给定行中的许多列都是空的。
  • @O.Jones 但这些表已经是 innodb (我现在已将其添加到我的帖子中),并且 ROW_FORMAT=DYNAMIC 无法修复它
  • 如何定义 varchars 以及您使用的字符集。错误发生在10.1版本吗?你想更新什么?你知道吗? :“在 MariaDB 10.2.26、MariaDB 10.3.17 和 MariaDB 10.4.7 之前,MariaDB 在执行 DDL 时无法正确计算行大小。在这些版本中,即使启用了 InnoDB 严格模式,也可以创建不安全的表MDEV-19292 在 MariaDB 10.2.26、MariaDB 10.3.17 和 MariaDB 10.4.7 中修复了计算。"

标签: mysql mariadb


【解决方案1】:

40 个字段定义为 varchar(250) DEFAULT NULL

所以SELECT MAX(LENGTH(col1)), ... 对于一些可能的列。

然后设计一个 ALTER 将一些最小的列缩小到较小的最大值,并将任何接近 250 的列更改为 TEXT

另外,请注意升级是否将 CHARACTER SET 更改为 latin1。

并注意您将要更改为 TEXT 的任何列是否在任何索引中。如果是这样,让我们​​更详细地讨论它们。

ALTER 需要很长时间,但可能不会像添加压缩一样长,当然也不会像更改页面大小那样长。)

MariaDB 10.3 引入了“Storage-engine Independent Column Compression”,可能有用。

【讨论】:

    【解决方案2】:

    我能够在 MySQL 5.7.34 上重现该错误(我不使用 MariaDB)。

    我能够通过将表更改为 ROW_FORMAT=COMPRESSED 并将列更改为数据类型 TEXT 而不是 VARCHAR 来解决错误。这两项更改都是必需的。带有 varchar 列的压缩行格式会导致相同的行大小错误。

    您可能已经知道这一点,但是您不能仅更改一张表的 InnoDB 页面大小。要更改页面大小,您必须转储所有表(或暂时将它们更改为 MyISAM 或其他存储引擎),然后关闭 mysqld,删除 InnoDB 表空间和日志,更改页面大小选项,然后重新启动 mysqld。它将在启动时使用新的页面大小初始化新的 InnoDB 表空间和日志。然后你可以将你的表改回 InnoDB。很明显,这会中断服务很长时间。

    替代方案可能是设置另一个具有更大页面大小的服务器实例,并在其中仅存储此单个表。

    但我同意 O.Jones 的上述评论——您应该重新考虑在同一行中存储 40 个长字符串列的表格设计。这种设计通常是归一化不当的结果。

    【讨论】:

    • 嗨@bill-karwin 感谢您的回复,但是我知道将列类型更改为 TEXT 将解决问题,ROW_FORMAT=COMPRESSED 不是必需的,因此您还没有真正提供答案,不过,关于额外服务器的评论很有趣,谢谢
    • @greebstreebling 测试时,我发现将列转换为数据类型 TEXT 是不够的。我必须这样做更改row_format。这两项更改都是必需的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-29
    • 2013-12-19
    • 2019-01-12
    • 1970-01-01
    • 2013-03-29
    相关资源
    最近更新 更多