在MySQL 8.0.12和MariaDB 10.3.2版本之前 对表加字段和索引是很常见的操作。但是对表加字段是加锁。
业界开发了一系列Online DDL的工具,包括MySQL官方也在不断的努力增强online DDL的便捷性。
1.Percona公司开发的pt-online-schema-change工具:
站点:https://www.percona.com/software/database-tools/percona-toolkit
原理概述:
通过触发器将新的数据变更到一个临时表,实际是在临时表DDL操作,采用替换的操作。
处理过程:
1.创建一个和要执行 alter 操作的表一样的新的空表结构(是alter之前的结构)
2.在新表执行alter table 语句(速度应该很快)
3.在原表中创建触发器3个触发器分别对应insert,update,delete操作
4.以一定块大小从原表拷贝数据到临时表,拷贝过程中通过原表上的触发器在原表进行的写操作都会更新到新建的临时表
5.Rename 原表到old表中,在把临时表Rename为原表
6.如果有参考该表的外键,根据alter-foreign-keys-method参数的值,检测外键相关的表,做相应设置的处理
7.默认最后将旧原表删除
弊端:当pt进行加字段的时候创建了三个触发器 而插入新表数据的时候是对原表加了S锁 当程序需要更新这个数据时候需要加一个X锁 就产生了死锁。
1.耗时较长
2.磁盘空间双倍
3.CPU负载较高
4.依然会有主从延迟
5.可能会有死锁
2.github开源的gh-osc:
站点:https://github.com/github/gh-ost
原理概述:
依赖于触发器,是因为他是通过模拟从库,在row binlog中获取增量变更,再异步应用到ghost表的。采用go语言开发。
DDL过程:
校验阶段:
1.检查有没有外键和触发器。
2.检查表的主键信息。
3.检查是否主库或从库,是否开启log_slave_updates,以及binlog信息
4.检查gho和del结尾的临时表是否存在
5.创建ghc结尾的表,存数据迁移的信息,以及binlog信息等
6.初始化stream的连接,添加binlog的监听
迁移阶段:
7.创建gho结尾的临时表,执行DDL在gho结尾的临时表上
8.开启事务,按照主键id把源表数据写入到gho结尾的表上,再提交,以及binlog apply。
cut-over阶段:
9.lock源表,rename 表:rename 源表 to 源_del表,gho表 to 源表。
10.清理ghc表。
3.Facebook开源的
站点:
https://github.com/facebookincubator/OnlineSchemaChange
原理:
采用python语言开发的online DDL.
https://github.com/facebookincubator/OnlineSchemaChange/wiki/How-OSC-works
4.MySQL 及MariaDB新加入的功能:instant add column
MySQL自身也在不断演进online DDL的功能:
MySQL 5.5 之前版本使用Copy Table方式通过临时表拷贝的方式实现的。新建一个带有新结构的临时表,将原表数据全部拷贝到临时表,然后Rename,完成创建操作。这个方式过程中,原表是可读的,不可写。但是会消耗一倍的存储空间。
MySQL 5.5 提供Inplace方式即在原表上直接进行,不会拷贝临时表。相对于Copy Table方式,这比较高效率。原表同样可读的,但是不可写。
MySQL 5.6 以上版本采用Online方式online方式支持DDL时不仅可以读,还可以写。
ALGORITHM=INPLACE,可以避免重建表带来的IO和CPU消耗,保证ddl期间依然有良好的性能和并发。
ALGORITHM=COPY,需要拷贝原始表,所以不允许并发DML写操作,可读。这种copy方式的效率还是不如 inplace ,因为前者需要记录undo和redo log,而且因为临时占用buffer pool引起短时间内性能受影响。
MySQL 8.0.12版本开始支持 instant add column。
参考: