更改实时生产数据库上的表


24

大多数“流行的”(MySQL,Postgres ...)数据库系统如何处理更改实时生产数据库上的表(如添加,删除或更改列的类型)?

我知道正确的方法是备份所有计划停机时间,然后进行更改。

但是...当前的数据库系统是否支持“在线”执行这些操作而不停止任何操作?(也许只是延迟引用刚被更改/删除的列的查询)

当我ALTER TABLE...在实时运行的数据库上进行操作时,会发生什么?发生这种情况时,一切都会停止吗?数据会损坏吗?等等

同样,我主要指的是Postgres或MySQL,因为它们是我遇到的。

(是的,是的,我必须在做“正确的方式”之前做任何事情,备份事情,安排例行工作……。但是我只是想知道是否有可能做这样的事情,而事情“很快又脏”或是否有任何数据库系统实际上支持“快速,活动和脏”模式更改)


有人刚才建议的在线模式修改为MySQL从Facebook脚本(有教程这里和源在这里)......似乎是一个很好的方式来自动执行了一套“哈克”的方式来做到这一点...有没有人用它在类似于生产吗?


3
注意:指定的“正确方法”是相对于MySQL而不是PostgreSQL。PostgreSQL中的“正确方法”通常很容易,尽管可能会涉及到。使用pg_reorg可以帮助解决更困难的情况。
肖恩(Sean)2012年

我希望有一个详细的视频,有人可以解释尽可能多的策略。
Sandeepan Nath

Answers:


22

当您ALTER TABLE在PostgreSQL中发出时,它将获得一个ACCESS EXCLUSIVE锁,该锁将阻止所有内容,包括SELECT。然而,这种锁可以非常简短,如果表不需要重新编写,没有新的UNIQUECHECKFOREIGN KEY限制需要昂贵的全表扫描,验证等。

如有疑问,通常可以尝试一下!PostgreSQL中的所有DDL都是事务性的,因此ALTER TABLE如果花费太长的时间取消并开始保留其他查询,则可以取消。锁定页面记录了各种命令所需的锁定级别。

可以加快某些通常较慢的操作的安全性,而无需停机。例如,如果你有表t,你想更改列customercode integer NOT NULLtext因为客户已经决定所有的客户代码必须现在有开始X,你可以写:

ALTER TABLE t ALTER COLUMN customercode TYPE text USING ( 'X'||customercode::text );

...但这将锁定整个表以进行重新写入。添加带有的列也是如此DEFAULT。可以通过几个步骤来完成此操作,以避免长时间锁定,但是应用程序必须能够应对临时复制:

ALTER TABLE t ADD COLUMN customercode_new text;
BEGIN;
LOCK TABLE t IN EXCLUSIVE MODE;
UPDATE t SET customercode_new = 'X'||customercode::text;
ALTER TABLE t DROP COLUMN customercode;
ALTER TABLE t RENAME COLUMN customercode_new TO customercode;
COMMIT;

这只会防止写入t在该过程; 锁的名称EXCLUSIVE是在一定程度上欺骗它排除一切除了SELECT ; 该ACCESS EXCLUSIVE模式是唯一不包含绝对内容的模式。请参阅锁定模式。由于要求进行锁升级,因此存在操作可能死锁回滚的风险ALTER TABLE,但是在最坏的情况下,您只需要重新执行一次即可。

你甚至可以避开锁,并通过创建触发器功能做全活的东西t,只要一个INSERTUPDATE到来时,会自动填充customercode_newcustomercode

还有一些内置工具,例如CREATE INDEX CONCURRENTLY和,它们ALTER TABLE ... ADD table_constraint_using_index旨在允许DBA通过以并发友好的方式更慢地进行工作来减少排他锁定时间。

pg_reorg工具或其后继工具pg_repack也可以用于某些表重组操作。


1
@Craig所说的关键是,“如果不需要重写的话”。ALTER TABLE t ADD COLUMN i INT一旦获得锁定,使用an 是一项快速操作(通常<1ms)。但是,获得锁可以使连接排队,因此它不是“免费的”……尽管它比您在MySQL中要做的要好得多。增加NOT NULL约束更加困难,而不是出于假装。
肖恩(Sean)

似乎已达成共识,它pg_repack是的改进后继产品pg_reorg
Erwin Brandstetter

关于添加具有默认值(或计算值)的列的好答案,一种较少“阻塞”的方式是创建整个新表,阻塞旧表以进行插入/更新/删除,但允许选择并填充新表。最后,在旧表上发出一个简短的排他锁以供选择,将其删除并将新名称重命名为old。根据您的情况,您甚至可以开始填充新文件而不会在旧文件中阻止插入,而仅在解决差异时才发出排他锁(希望只是插入一些新记录)
Jean

7

Percona提供了自己的工具来执行在线模式更改

该工具称为pt-online-schema-change

它涉及触发器,因此请仔细阅读文档。

根据文档,完成的主要操作是

  • 健全性检查
  • 块状
  • 在线模式变更
    • 创建和更改临时表
    • 捕获从表到临时表的更改
    • 将表格中的行复制到临时表中
    • 同步表和临时表
    • 交换/重命名表和临时表
    • 清理

谢谢,似乎是Facebook方法的“强化”版本,我可以相信更多...
NeuronQ 2012年

如果您正在运行自己的MySQL服务器,则pt-online-schema-change绝对是首选的方法。从Percona Tools 2.2开始,(不幸的是)它们不支持AWS上的RDS / Aurora。pt-online-schema-change在源表上插入一个触发器,以将行(MyISAM的低优先级)复制到目标table_temp,并在所有行在源和目标之间同步时执行一次快速锁定删除并在最后重命名表。
phpguru

6

关闭系统并立即进行所有更改可能会非常危险。如果出了问题,并且经常发生,就没有简单的方法。

作为一名敏捷开发人员,由于要修改和读取这些表,有时我需要重构这些表而没有任何停机时间。

以下方法具有较低的风险,因为更改是通过几个很容易回滚的低风险步骤完成的:

  • 确保自动测试覆盖了访问表的所有模块。
  • 创建一个新表。更改所有修改旧表的过程,以便它们同时修改旧表和新表。
  • 将现有数据迁移到新结构。批量进行此操作,以免严重影响服务器的整体性能。
  • 验证数据迁移成功。
  • 将某些选择过程从旧表重定向到新表。使用自动测试来确保更改后的模块仍然正确。确保其性能可接受。部署更改后的过程。
  • 重复上一步,直到所有报告都使用新表。
  • 更改修改表的过程,以使它们仅访问新表。
  • 存档旧表并将其从系统中删除。

我们已经多次使用这种方法来更改大型现场生产表,而无需停机,也没有任何问题。


3
很棒...但这正是我想要避免的“痛苦”类型:)
NeuronQ

@NeuronQ“ 没有简单的方法可以回去 ” -Postgres中存在:只需将所有内容放入事务中,rollback如果出现任何错误。
a_horse_with_no_name

2

是的,许多现代数据库都允许您仅添加列或更改列的特征,例如添加或删除可为空的值。

如果删除一列,数据将丢失,但没有太多担心损坏的担心。



-1

要解决有关ALTER TABLE语句会发生什么的问题,这取决于更改的程度。在特定情况下,如果至少在MS SQL Server中添加新列,则引擎将在创建新表定义的同时创建表的临时副本,然后将数据插入该表中。因此,在更改期间,用户将无法访问该表。

MSSQL服务器的特定操作的示例在这里:http : //support.microsoft.com/kb/956176/en-us

我将假定其他RMDB具有类似的方法,尽管确切的实现将需要您与供应商的文档进行验证。


-1这对于SQL Server是完全错误的:“如果至少在MS SQL Server中添加新列,则引擎将在创建新表定义的同时创建表的临时副本,然后再将数据插入回在那里”
AK

@AlexKuznetsov-我想出了上一行,以及列出的一些案例的链接将阐明这种情况并不总是发生。我修改了句子以更好地反映这一点。
SchmitzIT 2012年

1
您提到的是GUI,SSMS的行为,而不是SQL Server本身的行为。按照您的链接,建议是直接使用T-SQL进行DDL更改。SSMS并不是更改DDL的很好工具。
AK 2012年

@AlexKuznetsov-我读这篇文章时说的是涉及风险,但不是泄气。无论如何,我没有为GUI位链接文章,而是作为一些操作的指示,这些操作导致ALTER语句由于底层数据结构的变化而导致创建临时表。我没有测试直接从T-SQL发出语句时是否适用完全相同的方法,但是我认为该过程非常相似,并且SL Server在后台进行了繁琐的工作。
SchmitzIT 2012年

您可以启动Profiler,直接执行ALTER TABLE语句,然后看看发生了什么。然后,您可以通过对话框更改表,并亲自查看正在执行的命令。
AK 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.