你如何处理改变生产MySQL数据库模式的任务?

我听说过有关MySQL的最大抱怨之一是,如果尝试更改其架构(如添加列或添加索引),则会locking表。

“locking桌子”是否意味着我既不能读也不能写信给桌子? 有时几个小时?

这似乎是一个非常严重的限制。 我正在为我的新项目使用MySQL,但这让我停下来。

有没有解决方法? 你如何处理改变生产MySQL数据库模式的任务?

顺便说一句,有人告诉我Postgresql没有这个问题。 这是真的 – 我可以读写一个Postgresql表,同时改变它的模式? 是否有任何性能损失?

很想听听你的经验。

是的,MySQL在完成ALTER TABLE语句的同时完全locking表。 大部分时间都花在物理复制表上,这就是为什么build议您将所有必要的更改放在一个ALTER TABLE语句中。

如果您无法获得体面的维护时间,有几种方法可以减轻活动数据库中的这个问题。

首先,许多环境都有几分钟的等待时间,等待一个表可以用于查询,而不知道为什么表被locking(并且确实很难检查)。 我用一个现场网站的这个怪癖来改变表格。 在我曾经照顾过的一个网站上,我想我们有一个约7分钟的津贴,才有人开始注意。 :-)这有助于确保你的老板在你身边。

另一种方法是做select-insert-rename技巧。 如果表格的UPDATE频率相当低,或者纯粹是INSERT的目标,那么效果很好。 基本的步骤是复制表格的模式,进行必要的修改,创build一个语句来执行从旧到新的INSERT...SELECT ,并重命名表(在一个语句中重命名)。 您还需要提前准备一份声明,以复制在SELECTRENAME之间添加或更新的所有“新”logging。 在过去的工作中,我也做了几次。

但是,有一些警告:

  • 如果源表是MyISAM,那么几乎肯定会遇到问题,除非表可能永远不会写入。 这是因为MyISAM表locking的方式。 它对InnoDB表更好,因为在INSERT...SELECT正在运行的时候它仍然可以被读取。
  • 你需要一个简单的方法来确定在SELECTRENAME之间添加或改变的logging。 对于仅用于INSERT ,请使用auto_increment列。 对于获取UPDATE的表,您将需要一个可靠的最后修改的列。

解决这个问题的其他方法包括修改从属服务器,并使应用程序失败。 这与数据库如何复制密切相关。 我自己也没有这样做,所以我不能描述确切的步骤。

最后,有十几个服务器设置可以旋转,还有几个更难更改,这将影响复制表格所需的时间。 sorting缓冲区是一个,但是MySQL允许使用多less内存是另一个。 (请记住,每个连接也可以设置很多,而不是在全局设置一些高数据。)在处理大量数据时,MySQL有一个“转折点”的效果,在某些情况下,大小,然后突然下地狱。 它经常会涉及到处理大量数据的复杂查询,并且与内部临时表大小以及允许使用多less内存有关,但是由于涉及到对数据进行重新索引,因此可以提供表更改。 这就是为什么给数据库更多的内存几乎总是一件好事。

这是你听说过的关于MySQL的最大抱怨? 吉兹,我有一桶比这更大的桶……(也许是另一天的故事)

是的,当你在其上运行一个ALTER TABLE时,MySQL会完全locking一个表; 没有读或写的持续时间,以及试图这样做的查询得到暂停,直到它完成。 在奇怪的情况下,我必须修改一个大的MySQL表(小的很快完成他们的变化,以至于不会引起一个明显的问题)的架构,我通常只是安排一个维护窗口,然后做。 对于复制品上的给定表格,这样的改变将花费多长时间并不困难。

如果你有一个白痴pipe理层拒绝让你有合理的维护窗口(如果是的话,就像下地狱一样工作),那么我听说有人在做一些表格模式的副本,修改空表,然后在新表中进行复制select(使用写锁来防止更改),然后重命名表。 听起来像我的味道太多的风险。 Maatkit的mk-table-sync有一个模式来做到这一点,如果你希望在死亡的时候能够责怪别人。

虽然PostgreSQL没有“巨大的厄运之谜”,但是仍然会在修改PgSQL中的表格模式方面造成显着的性能下降 – 这是大量的磁盘IO。 不过,我无法想象任何关系型数据库pipe理系统如何能够避免这种情况。