我听到的关于 MySQL 的最大抱怨之一是,如果您尝试更改其架构(例如添加列或添加索引),它会锁定表。
“锁定桌子”是否意味着我既不能读也不能写桌子?有时几个小时?
这似乎是一个相当严重的限制。我打算将 MySQL 用于我的新项目,但这让我暂停了。
有解决方法吗?您如何处理更改生产 MySQL 数据库架构的任务?
顺便说一句,有人告诉我 Postgresql 没有这个问题。这是真的吗 - 我可以在更改其架构的同时读取和写入 Postgresql 表?是否会产生任何性能损失?
很想听听你的经历。
是的,MySQL 在执行 ALTER TABLE 语句时会完全锁定表。大部分时间都花在物理复制表上,这就是为什么建议您将所有必要的更改放在一个 ALTER TABLE 语句中的原因。
如果您无法获得合适的维护窗口,有几种方法可以在实时数据库上缓解此问题。
首先,许多环境有几分钟的超时等待表可供查询,并且不知道(而且很难检查)表被锁定的原因。我已经使用实时网站的这个怪癖来更改表格。在我曾经照看的一个网站上,我认为我们在有人开始注意到之前有大约 7 分钟的时间。:-) 这有助于确保你的老板站在你这边。
另一种方法是执行 select-insert-rename 技巧。如果表具有相当低的
UPDATE
频率,或者纯粹是INSERT
s 的目标,则此方法效果很好。基本步骤是复制表的模式,进行必要的更改,制作一条语句以INSERT...SELECT
从旧到新,然后重命名表(在一个语句中进行重命名)。您还需要提前准备一份声明,以复制在SELECT
和之间添加或更新的任何“新”记录RENAME
。我在过去的工作中也做过几次。但是,有一些警告:
INSERT...SELECT
运行时读取。SELECT
和 之间添加或更改的记录RENAME
。对于仅用于 的表INSERT
,请使用 auto_increment 列。对于获得UPDATE
s 的表,您将需要一个可靠的 last-modified 列。解决此问题的其他方法包括修改从属设备并使应用程序失败。这与您的数据库如何复制更紧密相关。我自己也没有做过这个,所以我无法描述确切的步骤。
最后,您可以调整十几个服务器设置,还有几个更难更改的设置,这将影响复制表所需的时间。排序缓冲区是一个,但 MySQL 允许使用多少内存是另一个。(请记住,您也可以为每个连接设置很多,而不是全局设置其中一些。)当处理大量数据时,MySQL 有一个“临界点”效应,事情在一定程度上是相当线性的大小,然后突然下地狱。它经常提出处理大量数据的复杂查询,并且与内部临时表大小和允许使用多少内存有关,但它可能会提出表更改,因为它们涉及重新索引数据。这就是为什么为数据库提供更多内存几乎总是一件好事的一个原因。
这是你听过的关于 MySQL 的最大抱怨?天啊,我有一桶比那个更大的……(也许改天再说)
是的,当您在其上运行 ALTER TABLE 时,MySQL 会完全锁定一个表;在此期间没有读取或写入,并且尝试这样做的查询会暂停,直到完成。在奇怪的情况下,我必须修改大型 MySQL 表的模式(小型表完成更改的速度足够快,不会引起明显的问题),我通常只是安排一个维护窗口然后再做。对于副本上的给定表,准确地确定这种更改需要多长时间并不难。
如果你有一个白痴管理层拒绝让你有合理的维护窗口(如果是这样,那就跑到另一份工作去),那么我听说有人在做一些事情,比如复制一个表的模式,修改空表,然后对新表进行复制选择(使用写锁以防止更改),然后重命名表。听起来对我的口味来说风险太大了。Maatkit 的mk-table-sync有一个模式可以做到这一点,如果你希望在它死时能够责怪别人。
虽然 PostgreSQL 没有“巨大的厄运锁”,但在 PgSQL 中修改表的模式仍然会导致显着的性能损失——它需要大量的磁盘 IO。不过,我无法想象任何 RDBMS 将如何避免这种情况。