首先,用过数据库的朋友(本文以MySQLInnoDB为例)都知道,MySQL不仅有对数据的增删改查操作(DML),还有对数据的操作修改表结构(DDL)。添加新字段和修改表结构时,需要进行DDL操作。但是,如果对一个存储了数百万甚至数万条数据的数据表进行DDL操作,数据库是如何做的呢?会不会有大事务锁?会不会影响数据的插入和更新??今天我们就来谈谈这个问题,以及PT-OSC、GH-OST等技术是如何高效解决这个问题的。MySQL5.5之前在MySQL5.5及更早版本中,DDL操作主要包括copytable和inplace。1、CopyTable方法CopyTable,顾名思义,就是通过复制一张临时表来实现的。在MySQL5.5及之前的版本中,修改表结构是表级的锁,所以在整个DDL过程中,表都是锁着的,不能写。这样很容易在修改时消耗数据库CPU、IO等性能,以及延迟主从同步。在上述过程中,MySQL自动完成转储数据、交换表名、删除旧表等操作。最耗时的过程是向临时表(Server层)插入数据的过程。在整个DDL过程中,表是不能执行DML的。2.IN-Place方法在MySQL5.5版本中,增加了IN-Place方法。所谓IN-Place方式就是直接在原表上创建索引,不需要复制整个表,只需要在原idb文件上创建需要的索引页,相比之下节省了大量的IO资源CopyTable,减少DDL执行时间。比较CopyTable和IN-Place这两种方式,再看官网(MySQL5.5)的内容:(引自:https://dev.mysql.com/doc/refman/5.5/en/alter-table.html)以上是MySQL5.5版本中的描述,MySQL5.6版本官方提出了COPY和INPLACE两种方式。(引自:https://dev.mysql.com/doc/refman/5.6/en/alter-table.html)3.FastIndexCreation(FIC)Innodb存储引擎从1.0.x版本开始,用于添加索引操作A引入了新功能快速创建索引(FIC功能)。FIC的意思是在添加或删除二级索引时,不复制原表,而是在创建或删除二级索引时,在原表上加一个S锁(共享锁),允许其他会话读,但禁止写操作,根据当前表数据创建索引。新索引创建完成后,释放S锁,允许写操作。FIC在创建索引时不需要复制全表数据,但只对二级索引有效,对主键索引无效。对于主键索引的创建和删除,需要重建一张临时表。比较IN-Place和FIC,在网上查了一些资料说“INPLACE方法也叫InnoDB快速创建索引”。这两个应该不是一回事吧?我们看一下官网(MySQL5.5)的内容:(引用自:https://dev.mysql.com/doc/refman/5.5/en/innodb-create-index-overview.html)在官方说明中MySQL5.5中,并没有明确说明FIC是INPLACE,在这个版本中FIC只支持二级索引和辅助索引的增删改查。在MySQL5.6的官方描述中,指出OnlineDDL特性是基于InnoDBFIC的。(引自:https://dev.mysql.com/doc/refman/5.6/en/innodb-online-ddl.html)在MySQL8.0的官方描述中,指出FIC是对在线DDL。(引用自:https://dev.mysql.com/doc/refman/8.0/en/glossary.html)所以,综上所述,“INPLACE方法也叫InnoDB快速创建索引”这句话是正确的,网上的DDL方法扩展了FastIndexCreation,逐步扩大了FIC的范围。由于MySQL5.6在MySQL5.6版本中引入了OnlineDDL。这个新特性解决了MySQL早期版本的DDL操作导致的锁表问题。在线DDL在执行过程中依然保证可读可写,不影响数据库对外提供的服务。.在线DDLAltertable....,ALGORITHM[=]{DEFAULT|INPLACE|COPY},LOCK[=]{DEFAULT|NONE|SHARED|EXCLUSIVE}ALGORITHM子句指定了DDL的执行方式,LOCK子句描述了要控制的锁类型DML的并发性。其中有些DDL语句不支持OnlineDDL的COPY方法,支持的则使用INPLACE方法。因为OnlineDDL是对更早的INPLACE方法的增强,INPLACE方法分为:RebuildsTable和No-RebuildsTable,看官方的内容(MySQL5.7):(引自:https://dev.mysql。com/doc/refman/5.7/en/innodb-online-ddl-operations.html)根据COPY和INPLACE的在线对比,COPY方式导出表中数据的存储位置叫做tmp_table,是在服务器层创建的临时表。通过INPLACE方法从表中重建的数据放在tmp_file中。这个临时文件是由InnoDB内部创建的,整个DDL过程都是在InnoDB内部完成的。OnlineDDL的实现过程主要包括三个阶段:初始化阶段、执行阶段、CommitTableDefinition阶段。我们看一下官方的内容(MySQL8.0):(引用自:https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-performance.html)下面详细描述一下这个过程三个过程:(1)初始化创建持有EXCLUSIVE_MDL锁的frm临时文件,禁止读写根据ALTER操作,确定执行过程(COPY、Online-Rebuilds、Online-No-Rebuilds)更新数据字典的内存对象如果需要Rebuilds,分配row_log对象记录增量如果需要Rebuilds,新建一个ibd临时文件(2)执行(如果只修改MetaData,则没有这样的操作)减少EXCLUSIVE-MDL锁,允许读写(COPYonly允许读取)记录执行周期生成的DML操作到row_log(仅Rebuilds需要)扫描旧表记录的聚簇索引中的每条记录遍历新表的聚簇索引和二级索引,根据记录一条一条处理构造对应的索引项将构造好的索引项插入到sort_buffer块中将sort_buffer块插入到一个新的索引中,将row_log中的记录应用到新的临时表中,并应用到最后一个Block(3)CommitTableDefinitionupgradetoEXECLUSIVE-MDL锁,禁止读写redo,增量更新最后一部分row_logInnoDB数据字典中提交事务,写入InnoDBredologs,修改统计信息,重命名临时ibd和frm文件,执行DDL变更。我理解OnlineDDL中COPY和INPLACE的区别在于有没有in-place。COPY会将数据从InnoDB存储层复制到Server层,而INPLACE不会;而INPLACE中Rebuilds和No-Rebuilds的区别在于是否有重建表。PT-Online-Schema-Change(PT-OSC)的全称是PerconaToolkitOnlineSchemaChange。PerconaToolkit源自Maatkit和Aspersa工具。这两个工具是最著名的管理MySQL的工具,但是Maatkit已经不再维护了,都合并了。到Percona工具包。PerconaToolkit是一组用于管理MySQL和系统任务的高级命令行工具。PT-OSC(pt-online-schema-change)工具的特点和优势是支持并发DML操作。GitHub的在线模式转换器(GH-OST)GH-OST是GitHub的在线表定义转换器。与PT-OSC最大的区别在于GH-OOST的免触发设计。至此,我们已经比较了OnlineDDL、PT-OSC和GH-OST的优缺点:(引自:吴侠《在线DDL原理、对比分析和实践》)总结一下传统的DDL,大多数ALTERTABLE操作都是通过创建满足的新表来创建的需求,然后复制数据到新表,用新表替换旧表时,整个过程会被锁住,不支持并发DML。MySQL5.5以InnoDBPlugin的方式优化了增删索引操作,避免了数据拷贝的开销,出现了FIC。从MySQL5.6开始,增强了对各种ALTERTABLE操作的支持,以避免数据复制的开销,同时允许在进行DDL的同时并发执行DML操作。MySQL5.7实现了ALTERTABLERENAMEINDEX操作,支持在线索引重命名。这个特性的综合就是ONLINEDDL。PT-OST通过对原生DDL的改造,实现了表结构的在线修改,无需锁表。【本文为专栏作者张凯涛原创文章,作者微信公众号:凯涛的博客,id:kaitao-1234567】点此阅读作者更多好文
