ALTER TABLE没有locking表?
在MySQL中执行ALTER TABLE语句时,在整个语句期间整个表都被读取locking。 如果这是一张大桌子,这意味着插入或更新语句可能会被locking一段时间。 有没有办法做一个“热点改变”,如添加一个列的方式,表中仍然可以更新整个过程?
大多数情况下,我对MySQL的解决scheme感兴趣,但如果MySQL不能这样做,我会对其他RDBMS感兴趣。
为了澄清,我的目的只是为了避免需要额外的表列的新function推到生产时的停机时间。 任何数据库模式都会随着时间而改变,这只是一个事实。 我不明白为什么我们应该接受这些改变不可避免地会导致停机; 这只是弱。
唯一的其他select是手动执行许多RDBMS系统的function。
– 创build一个新表
然后,您可以一次将旧表的内容复制到一个块上。 同时始终谨慎的源表上的任何INSERT / UPDATE / DELETE。 (可以通过触发器进行pipe理,虽然这会导致速度变慢,但这不是locking)
完成后,更改源表的名称,然后更改新表的名称。 最好在交易中。
完成后,重新编译任何使用该表的存储过程等。 执行计划可能不再有效。
编辑:
一些评论已经被提出这个限制有点差。 所以我想我会用一个新的angular度来说明为什么它是这样的…
- 添加一个新的字段就像改变每一行的一个字段。
- 现场锁将比行锁更难,不用pipe桌锁。
- 你实际上正在改变磁盘上的物理结构,每一个logging都会移动。
- 这真的就像整个表上的更新,但影响更大…
Percona提供了一个名为pt-online-schema-change的工具,可以完成这个工作。
它本质上是复制表格并修改新表格。 为了保持新表与原来的同步,它使用触发器来更新。 这允许在后台准备新表时访问原始表。
这与上面提到的Demsbuild议的方法类似,但是这是以自动方式进行的。
他们的一些工具有一个学习曲线,即连接到数据库,但一旦你有这个工具,它们是很好的工具。
例如:
pt-online-schema-change --alter "ADD COLUMN c1 INT" D=db,t=numbers_are_friends
查看Facebook的在线模式更改工具。
http://www.facebook.com/notes/mysql-at-facebook/online-schema-change-for-mysql/430801045932
不是因为心里的隐隐; 但它会做的工作。
我推荐Postgres,如果这是一个选项。 有了postgres,下面的程序基本上没有停机时间:
- ALTER TABLE ADD COLUMN(如果列可以是NULL)
- 改变表删除列
- CREATE INDEX(必须同时使用CREATE INDEX)
- DROP INDEX
其他强大的function是大多数DDL语句都是事务性的,所以您可以在SQL事务中完成整个迁移,如果出现问题,整个事情会回滚。
我之前写过这个 ,或许可以对其他优点有更多的了解。
这个问题从2009年开始。
在线DDL
在DDL(主要是ALTER TABLE)操作期间改进InnoDB表的性能,并发性和可用性的一项function。 有关详细信息,请参见第14.11节“InnoDB和Online DDL”。
细节因操作types而异。 在某些情况下,可以在ALTER TABLE正在进行的同时修改表。 该操作可以在不执行表副本的情况下执行,也可以使用专门优化types的表副本来执行。 空间使用率由innodb_online_alter_log_max_sizeconfiguration选项控制。
它允许您通过select是否完全阻止对表的访问(LOCK = EXCLUSIVE子句),允许查询而不是DML(LOCK = SHARED子句),或允许完整查询和DML来调整DDL操作期间性能和并发之间的平衡访问表(LOCK = NONE子句)。 当您省略LOCK子句或指定LOCK = DEFAULT时,MySQL允许尽可能多的并发操作,具体取决于操作的types。
在可能的情况下就地进行更改,而不是创build表的新副本,从而避免临时增加与复制表和重新构build二级索引相关的磁盘空间使用情况和I / O开销。
有关更多信息,请参阅MySQL 5.6参考手册 – > InnoDB和Online DDL 。
看来,在MariaDB中也可以使用在线DDL
或者,您可以使用ALTER ONLINE TABLE来确保您的ALTER TABLE不会阻止并发操作(不locking)。 它相当于LOCK = NONE。
关于ALTER TABLE的MariaDB KB
由于您询问了其他数据库,下面是一些关于Oracle的信息。
将一个NULL列添加到Oracle表是一个非常快速的操作,因为它只更新数据字典。 这在很短的时间内在桌子上独占锁。 然而,它将使所有的存储过程,视图,触发器等无效。这些将自动重新编译。
如有必要,可以使用ONLINE子句创build索引。 再次,只有非常短的数据字典锁。 它会读整个表寻找索引的东西,但不会阻止任何人这样做。
如果您需要添加外键,则可以执行此操作,让Oracle相信您的数据是正确的。 否则,需要读取整个表格并validation所有可能较慢的值(首先创build索引)。
如果您需要将默认值或计算值放入新列的每一行,则需要运行一个大规模更新或者一个填充新数据的小型实用程序。 这可能是缓慢的,特别是如果行得到更大,不再适合他们的块。 locking可以在这个过程中进行pipe理。 由于应用程序的旧版本仍处于运行状态,因此无法了解此列,因此可能需要一个隐藏的触发器或指定一个默认值。
从那里,你可以在你的应用程序服务器上做一个switcharoo到新版本的代码,它会继续运行。 放下你偷偷摸摸的触发器。
或者,您可以使用DBMS_REDEFINITION这是一个黑盒子devise来做这种事情。
所有这一切都是非常麻烦testing等,我们只是有一个星期天早上中断,每当我们发布一个主要版本。
不。 如果你正在使用MyISAM表,尽我所能了解他们只做表锁 – 没有logging锁,他们只是试图通过简单的方式保持一切超高速。 (其他MySQL表的操作方式不同。)无论如何,您可以将表复制到另一个表中,对其进行更改,然后切换它们,更新差异。
这是如此巨大的变化,我怀疑任何数据库pipe理系统会支持它。 首先可以用表格中的数据来处理它,这被认为是一个好处。
如果您在执行应用程序更新时无法承担数据库停机时间,则应考虑维护双节点群集以实现高可用性。 通过简单的复制设置,您可以完成几乎完全的在线结构更改,如您所build议的:
- 等待所有更改被复制到被动从站上
- 将被动从机改为主动主机
- 对老主人做结构性的改变
- 将更改从新主控台复制到旧主控制台
- 再次进行主交换和新的应用程序部署
它并不总是很容易,但它的工作原理,通常与0停机时间! 第二个节点不一定是被动的,它可以用于testing,做统计或作为备用节点。 如果您没有基础架构复制,可以在单台机器(具有两个MySQL实例)中进行设置。
临时解决scheme…
其他解决scheme可能是,与原始表的主键一起添加另一个表,以及您的新列。
将主键填充到新表中,并在新表中填充新列的值,然后修改查询以join此表以进行select操作,并且还需要分别为此列值插入和更新。
如果能够停机,可以更改原始表,修改DML查询并删除之前创build的新表
否则,你可能会从percona去集群方法,复制,pt-online-schema工具
使用Innodb插件,只需添加或删除二级索引的ALTER TABLE语句可以“快速”完成,即不需要重build表。
但是,一般来说,在MySQL中,任何ALTER TABLE都涉及重build整个表,这可能需要很长时间(例如,如果表中有有用的数据量)。
您确实需要devise您的应用程序,以便ALTER TABLE语句不需要定期完成; 除非你准备等待,或者你正在改变小桌子,否则你肯定不希望在应用程序正常运行期间完成任何ALTER TABLE。
一般来说,答案将是“否”。 你正在改变表的结构,这可能需要大量的更新“我绝对同意这一点,如果你期望经常这样做,那么我会提供一个替代”虚拟“列 – 使用VIEW
s而不是用于SELECT
数据的表IIRC,改变视图的定义是相对轻量级的,而通过视图的间接是在编译查询计划的时候完成的,代价是你必须把列添加到新表中,在列中使视图JOIN
。
当然,这只有在你可以使用外键来执行级联的删除和什么的情况下才有效。 另外一个好处就是你可以创build一个包含数据组合的新表格,并且在不影响客户端使用的情况下指向它。
只是一个想法。
正如SeanDowney所提到的, pt-online-schema-change
是你在这个问题中描述的最好的工具之一。 我最近在一个活的数据库上进行了大量的模式更改,并且进行得非常顺利。 你可以在我的博客文章阅读更多关于它: http : //mrafayaleem.com/2016/02/08/live-mysql-schema-changes-with-percona/ 。
你一定要尝试pt-online-schema-change
。 我一直使用这个工具在AWS RDS上用多个从机进行迁移,对我来说工作得非常好。 我写了一篇详细的博客文章,介绍如何做到这一点可能对你有所帮助。
博客: http : //mrafayaleem.com/2016/02/08/live-mysql-schema-changes-with-percona/
如果你能预测它们的types(并使它们为空),虚拟列是一个好主意。 检查您的存储引擎如何处理空值。
MyISAM将locking所有的东西,如果你甚至在机场通过电话,手机提及表名。 这只是…
这就是说,锁并不是什么大事; 只要你不试图为每一行添加一个新列的默认值,而是让它为空,并且你的存储引擎足够聪明,不要去写它,你应该确定只有一个锁持续足够长的时间来更新元数据。 如果你试图写一个新的价值,那么你就是敬酒。
我会推荐两种方法之一:
-
devise你的数据库表,考虑到潜在的变化。 例如,我曾与内容pipe理系统(Content Management Systems)合作,定期更改内容中的数据字段。 不build立物理数据库结构来匹配最初的CMS领域需求,而是build立一个灵活的结构要好得多。 在这种情况下,使用blob文本字段(例如varchar(max))来保存灵活的XML数据。 这使得结构变化非常频繁。 结构变化可能是昂贵的,所以在这里也有成本的好处。
-
有系统维护时间。 系统在更改期间(每月等)都处于脱机状态,并且将在一天中最less的繁忙时间(例如上午3-5点)进行更改。 在生产推出之前,这些变化是分阶段的,所以你将有一个很好的固定窗口的停机时间估计。
2A。 有冗余的服务器,这样当系统停机时,整个站点不会停机。 这样可以让你以一种交错的方式“滚动”你的更新,而不必把整个网站都放下。
选项2和2a可能不可行; 他们倾向于只为更大的站点/操作。 然而,他们是有效的select,我个人使用了这里提出的所有选项。
如果有人还在读这篇文章或碰巧来到这里,这是使用MongoDB等NoSQL数据库系统的一大好处。 我有同样的问题处理改变表,要么添加列的附加function或索引在一个大型的数百万行和高写入的表。 最终会locking很长一段时间,所以在LIVE数据库上这样做会让我们的用户感到沮丧。 在小桌子上,你可以摆脱它。
我讨厌我们必须“devise我们的桌子,以避免改变他们”。 我只是不认为这在今天的网站世界。 你无法预测人们如何使用你的软件,这就是为什么你根据用户反馈迅速改变的原因。 有了mongodb,您可以随意添加“列”,而不会停机。 你甚至不会添加它们,只需要插入新列的数据并自动完成。
值得检查:www.mongodb.com
TokuDB可以添加/删除列和添加索引“热”,该表是完全可用的整个过程。 它可以通过www.tokutek.com获得
Postgres和MySQL在这方面的区别是在Postgres中它不会重新创build表,而是修改类似于Oracle的数据字典。 因此,操作速度很快,而其他人则需要在非常短的时间内分配独占的DDL表锁。
在MySQL中,操作会将数据复制到一个新表中,同时阻止事务,这在5.6版之前一直是MySQL DBA的主要难题。
好消息是,自MySQL 5.6发布以来,这个限制已经大部分被解除了 ,现在你可以享受MYSQL DB的真正威力了。
不是真的。
毕竟,你正在改变表的底层结构,这对于底层系统是非常重要的一些信息。 你也(可能)在磁盘上移动大部分数据。
如果你打算做这么多事情,最好只用填充“虚拟”列的表格来填充表格,以备将来使用。