【问题标题】:Optimizing MySQL for ALTER TABLE of InnoDB针对 InnoDB 的 ALTER TABLE 优化 MySQL
【发布时间】:2010-10-13 20:47:17
【问题描述】:

很快我们将需要对生产数据库进行架构更改。我们需要尽量减少这项工作的停机时间,但是,ALTER TABLE 语句将运行相当长的一段时间。我们最大的表有1.5亿条记录,最大的表文件是50G。 所有表都是 InnoDB,并且它被设置为一个大数据文件(而不是一个文件每个表)。 我们在 8 核机器、16G 内存和 RAID10 配置上运行 MySQL 5.0.46。

我有一些 MySQL 调优的经验,但这通常侧重于来自多个客户端的读取或写入。在 Internet 上可以找到很多关于这个主题的信息,但是,关于(临时)调整 MySQL 服务器以加速 InnoDB 表上的 ALTER TABLE 或 INSERT INTO 的最佳实践的信息似乎很少。 . SELECT FROM(我们可能会使用它而不是 ALTER TABLE 以获得更多机会来加快速度)。

我们计划进行的架构更改是向所有表添加一个整数列,并使其成为主键,而不是当前的主键。我们还需要保留“旧”列,因此不能覆盖现有值。

让这项任务尽快完成的理想设置是什么?

【问题讨论】:

标签: mysql alter-table performance


【解决方案1】:

我测试了各种策略来加速一个 alter table。最终,在我的特定情况下,我的速度提高了大约 10 倍。结果可能适用于您的情况,也可能不适用于您的情况。但是,基于此,我建议尝试使用 InnoDB 日志文件/缓冲区大小参数。

简而言之,只有增加 innodb_log_file_size 和 innodb_log_buffer_size 才会产生可衡量的效果(小心!更改 innodb_log_file_size 有风险。请参阅下文了解更多信息)。

根据粗略的写入数据速率 (iostat) 和 cpu 活动,瓶颈是基于 io 的,而不是数据吞吐量。在更快的 500 秒运行中,写入吞吐量至少与您对硬盘的预期相同。

尝试了性能优化:

更改 innodb_log_file_size 可能很危险。请参阅http://www.mysqlperformanceblog.com/2011/07/09/how-to-change-innodb_log_file_size-safely/链接中解释的技术(文件移动)在我的情况下效果很好。

另请参阅 http://www.mysqlperformanceblog.com/2007/11/03/choosing-innodb_buffer_pool_size/http://www.mysqlperformanceblog.com/2008/11/21/how-to-calculate-a-good-innodb-log-file-size/ 了解有关 innodb 和调整日志大小的信息。较大日志文件的一个缺点是崩溃后的恢复时间较长。

测试运行和粗略的时间安排:

  • 将数据简单加载到新创建的表中:6500s
  • 加载数据w。 innodb_log_file_size=200M,innodb_log_buffer_size=8M,innodb_buffer_pool_size=2200M,自动提交= 0; unique_checks=0, foreign_key_checks=0: 500s
  • 加载数据w。 innodb_log_file_size=200M, innodb_log_buffer_size=8M: 500s
  • 等效的直接更改表 w。 datainnodb_log_file_size=200M, innodb_log_buffer_size=8M: 500s

测试细节:表:InnoDB,6M 行,2.8G 磁盘,单个文件(innodb_file_per_table 选项),主键是 1 个整数,+2 非队列约束/索引,8 列,平均。行长 218 字节。服务器:Ubuntu 12.04,x86_64,虚拟机,8 核,16GB,sata 消费级磁盘,无 raid,无数据库活动,极少的其他进程活动,其他小得多的虚拟机中的极小活动。 mysql 5.1.53。初始服务器配置是非常默认的,除了增加了 1400M 的 innodb_buffer_pool_size。 alter 表添加了 2 个小列。我没有对原始的 alter table 计时,而是尝试了等效的 load data infile 语句,最后我做了直接的 alter table 并得到了可比较的结果。

这个问题至少与以下问题有关:

【讨论】:

  • 很棒的答案,这值得更多的投票。感谢您发表您的研究和结果。
【解决方案2】:

您可能想查看 Percona 工具包中的 pt-online-schema-change。本质上它的作用是:

  • 复制原始表结构,运行 ALTER。
  • 将旧表中的行复制到新创建的表中。
  • 使用触发器在复制时跟踪和同步更改。
  • 当一切都完成后,它通过重命名两个表来交换表。

对于单实例数据库非常有效,但如果您使用复制可能会非常棘手,并且您无法停止从属服务器并在以后重新构建它们。

还有一个关于 here 的精彩网络研讨会。

PS:我知道这是一个老问题,只是在有人通过搜索引擎点击的情况下回答。

【讨论】:

  • 来自 pt-online-schema-change 文档的注释:触发器的使用意味着如果表上已经定义了任何触发器,该工具将无法工作。
【解决方案3】:
  1. 设置从站
  2. 停止复制。
  3. 在从属设备上进行 ALTER
  4. 让slave追上master
  5. 交换主机和从机,使从机成为结构改变且停机时间最短的生产服务器

【讨论】:

    【解决方案4】:

    不幸的是,这并不总是像staticsan 在他的回答中提到的那么简单。在线创建新表并移动数据很容易,在维护模式下进行清理也很容易,但是,Mysql RENAME 操作会自动操作对旧表的任何外键引用。这意味着对原始表的任何外键引用仍将指向您将表重命名为的任何内容。

    因此,如果您对要更改的表有任何外键引用,那么您要么更改这些表以替换对新表的引用,要么更糟的是,如果该表很大,您必须重复处理大表号 2。

    过去对我们有用的另一种方法是处理一组 Mysql 副本来处理变更。我不是最适合谈论这个过程的人,但它基本上包括中断对一个从属的复制,在该实例上运行补丁,一旦改变表完成就重新打开复制,以便它赶上复制。一旦复制赶上,您将站点置于维护模式(如有必要)以从您的主数据库切换到这个新修补的从属数据库作为新的主数据库。

    我唯一不记得的事情是你将其他奴隶指向新主人的确切时间,以便他们也应用改变。对此过程有一个警告,我们通常使用它在代码需要更改之前或在代码更改为不再引用列/键之后滚动更改补丁。

    【讨论】:

    • 我没有想到外键。当我是一名 DBA 时,我使用了我所描述的技术,我们根本没有使用外键,因为应用程序相信它,只有它处理了所有这些。
    【解决方案5】:

    您需要更仔细地考虑您的要求。

    在最简单的级别上,更改表的“最快”方法是在尽可能少的 ALTER TABLE 语句中完成,最好是一个。这是因为 MySQL 复制表的数据以更改架构并进行 15 次更改,同时进行一次复制显然(并且确实)比复制表 15 次、一次进行一项更改要快。

    但我怀疑您问的是如何以最少的停机时间进行此更改。我这样做的方式,你基本上综合了非块ALTER TABLE 的工作方式。但它有一些额外的要求:

    1. 您需要一种方法来跟踪添加和更改的数据,例如为后者使用“修改”日期字段,或为前者使用AUTO_INCREMENT 字段。
    2. 您需要空间才能在数据库中保存两个表副本。
    3. 您需要一个时间段,在此时间段内对表的更改不会比快照提前太多

    基本技术如您所建议的那样,即使用INSERT INTO ... SELECT ...。至少你在前面,因为你从 InnoDB 表开始,所以 SELECT 不会阻塞。我建议在新的空表上执行 ALTER TABLE,这将保存 MySQL 再次复制所有数据,这意味着您需要在 INSERT INTO ... SELECT ... 语句中正确列出所有字段。然后你可以做一个简单的RENAME 语句来交换它。然后你需要再做一次INSERT INTO ... SELECT ... WHERE ... 或者UPDATE ... INNER JOIN ... WHERE ... 来获取所有修改过的数据。 您需要执行INSERTUPDATE 快速,否则您的代码将开始向您的快照添加新行和更新,干扰您的更新。 (如果您可以在RENAME 之前将应用程序置于维护模式几分钟,则不会出现此问题。)

    除此之外,您还可以为一个会话更改一些与键和缓冲区相关的设置,这些设置可能有助于主要数据的移动。像read_rnd_buffer_sizeread_buffer_size 这样的东西会很有用增加。

    【讨论】:

      【解决方案6】:

      我真的不知道如何优化它,但在进行此类更新之前将网站置于离线模式通常是一个好习惯。

      然后,您可以在凌晨 3 点运行您的 DB 脚本,因此如果停机时间比理想时间长很多,这应该没什么关系。

      【讨论】:

      • 是的——我们会在夜间关闭网站来完成这项任务。但是对于这么大的桌子,ALTER TABLE 可能会运行好几个小时,而这可能不适合一晚:(
      • 也许您想在单独的服务器上运行脚本,并转储生产数据库计时它需要多少时间。希望,你会得到一个不错的惊喜! :)
      • 是的,我们正在为此准备一个 QA 环境。如果不测试您的优化,就无法优化;)
      猜你喜欢
      • 1970-01-01
      • 2012-09-01
      • 2013-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-20
      • 1970-01-01
      • 2010-12-04
      相关资源
      最近更新 更多