适用于MySQL的事务性DDL工作流程


25

我有点惊讶地发现,DDL语句(alter tablecreate index等)隐含在MySQL提交当前事务。来自MS SQL Server,能够在本地事务中进行数据库更改(然后被回滚)的能力是我工作流程的重要组成部分。对于连续集成,如果由于某种原因导致迁移失败,则使用回滚,以便至少我们不会使数据库处于半迁移状态。

人们在将MySQL与迁移和持续集成结合使用时如何解决这两个问题?


从SO交叉发布。 stackoverflow.com/q/28197013/614523在那儿没有得到太多的爱。
sennett

1
对于持续集成,请将LVM快照视为一种非常快速地创建处于已知状态的整个环境的方法。
里克·詹姆斯

5
您可以随时升级到Postgres-它确实支持事务性DDL(SCNR)。
a_horse_with_no_name 2015年

3
我同意@a_horse_with_no_name,如果这是您的工作流程,请认真考虑使用PosgreSQL,它具有事务性DDL和许多其他不错的功能。
Renzo

Answers:


9

对于许多人来说,MySQL Achilles的缺点是隐式提交。

根据该书第418页第3段

MySQL 5.0认证学习指南

以下命令可以并且将中断交易

  • ALTER TABLE
  • BEGIN
  • CREATE INDEX
  • DROP DATABASE
  • DROP INDEX
  • DROP TABLE
  • RENAME TABLE
  • TRUNCATE TABLE
  • LOCK TABLES
  • UNLOCK TABLES
  • SET AUTOCOMMIT = 1
  • START TRANSACTION

建议

对于MySQL,您构造的任何ContinuousIntegration(CI)/ SelfService作业都应始终使事务性作业和DDL脚本互斥。

这为您提供了创建范例的机会,

  • 支持使用START TRANSACTION/COMMIT区块正确隔离的交易
  • 通过自己编写DDL脚本来控制DDL,并以构造函数或析构函数的形式运行DDL
    • 构造函数:DDL使用新设计制作表格
    • 析构函数:DDL使表恢复为先前的设计
  • 切勿将这些操作归于一项工作

警告:如果您正在使用MyISAM进行此操作,则可以(不)将MyISAM添加到可能中断事务的事物列表中,可能不是隐式提交,而是绝对要在数据一致性方面进行回滚需要。

为什么不使用LVM?

LVM快照非常有用,并且理想的是恢复数据库的整个实例而不必执行繁重的SQL处理。但是,对于MySQL,您必须考虑两个存储引擎:InnoDB和MyISAM。

All-InnoDB数据库

看看InnoDB的体系结构(图片由Percona CTO Vadim Tkachenko提供)

InnoDB管道

InnoDB有很多活动的部分

  • 系统表空间
    • 数据字典
    • 双重写入缓冲区(支持数据一致性;用于崩溃恢复)
    • 插入缓冲区(将缓冲区更改为二级非唯一索引)
    • 回滚段
    • 撤消空间(可能发生最不受控制的增长)
  • InnoDB缓冲池
    • 脏数据页
    • 脏索引页
    • 非唯一索引的更改
  • 其他重要的内存缓存

拍摄所有InnoDB数据库的LVM快照,并在缓冲区池和内存缓存中浮动未提交的更改,这将产生一个数据集,一旦恢复LUN并启动mysqld,该数据集将需要InnoDB崩溃恢复。

对全InnoDB的建议

如果可以在拍摄快照前关闭MySQL

    1. SET GLOBAL innodb_fast_shutdown = 0;
    1. SET GLOBAL innodb_max_dirty_pages_pct = 0;
    1. SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
    1. 重复步骤3,直到Innodb_buffer_pool_pages_dirty为0或尽可能接近0
    1. service mysql stop
    1. 拍摄LVM快照
    1. service mysql stop

如果您无法关闭但使用MySQL Live进行快照

    1. SET GLOBAL innodb_max_dirty_pages_pct = 0;
    1. SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
    1. 重复步骤2,直到Innodb_buffer_pool_pages_dirty为0或尽可能接近0
    1. 拍摄LVM快照
    1. SET GLOBAL innodb_max_dirty_pages_pct = 75;

全MyISAM数据库或InnoDB / MyISAM混合

当访问MyISAM时,将维护针对它的打开文件句柄数。如果MySQL崩溃,则任何打开文件句柄计数> 0的MyISAM表都将被标记为崩溃,需要修复(即使数据没有问题)。

还原快照并启动mysqld时,对使用MyISAM表的数据库进行LVM快照将需要修复一个或多个MyISAM表。

建议使用全MyISAM或InnoDB / MyISAM混合

如果可以在拍摄快照前关闭MySQL

    1. SET GLOBAL innodb_fast_shutdown = 0;
    1. SET GLOBAL innodb_max_dirty_pages_pct = 0;
    1. SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
    1. 重复步骤3,直到Innodb_buffer_pool_pages_dirty为0或尽可能接近0
    1. service mysql stop
    1. 拍摄LVM快照
    1. service mysql stop

如果您无法关闭但使用MySQL Live进行快照

您可以强制刷新某些InnoDB表

    1. SET GLOBAL innodb_max_dirty_pages_pct = 0;
    1. SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
    1. 重复步骤2,直到Innodb_buffer_pool_pages_dirty为0或尽可能接近0
    1. FLUSH TABLES innodb_tbl1,... FOR EXPORT;在关键的InnoDB表上运行
    1. FLUSH TABLES WITH READ LOCK;
    1. 拍摄LVM快照
    1. UNLOCK TABLES;
    1. SET GLOBAL innodb_max_dirty_pages_pct = 75;

MySQL复制可以帮助吗?

虽然您可以将一个LVM快照还原到两台服务器并设置MySQL Master / Slave Replication,但在还原快照时,这将成为清理房间的额外来源。

如果在主服务器上运行CI作业而这些作业很小,则在某些情况下复制可能会节省时间。您可以STOP SLAVE;在从站上运行START SLAVE;,在主服务器上启动CI作业,然后在验证主站数据后在从站上运行。

如果CI作业警告了太多数据,则可以从头还原LVM快照并设置复制。如果您发现自己经常这样做,则可以设置MySQL复制。

最后的想法

  • 最好使用多个数据库服务器(3个或更多)来执行还原和回归测试。
  • 如果不需要将剩余的MyISAM表保留为MyISAM,则将其转换为InnoDB。
  • 如果数据内容敏感,则应在还原快照后执行CI作业以清理数据,然后再启动任何测试。作为替代方案,您可能希望使用已清除数据的MySQL快照。

4

如果您谈论持续集成,那么我认为这是一个开发环境。在那种情况下,我想说做结构更改的人必须测试它们,以确保不会破坏他人的工作,就像更新公用库的人一样:在提交此类更改之前,请在您自己的沙箱中进行测试。

在生产部署过程中,您通常会经历开发,QA甚至生产前环境来测试您的更改,就像对任何代码更改一样。

请注意,这并非特定于MySQL:Oracle数据库在发出“ alter table”等内容时也会隐式执行COMMIT。

现在,如果您想保护自己,那么您当然可以事先进行备份,或者,如果系统可以这样做,则可以进行LVM或文件系统快照。您也可能有一个从站,为了安全起见,您可以在敏感操作之前将其延迟/停止。

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.