背景


dba的日常工作肯定有一项是ddl变更,ddl变更会锁表,这个可以说是dba心中永远的痛,特别是执行ddl变更,导致库上大量线程处于“Waiting for meta data lock”状态的时候。因此mysql 5.6的online ddl特性是dba们最期待的新特性,这个特性解决了执行ddl锁表的问题,保证了在进行表变更时,不会堵塞线上业务读写,保障在变更时,库依然能正常对外提供访问。网上关于online ddl的文章很多,但涉及原理的很少,都是介绍语法之类的,本文将详细介绍online ddl的原理,知其然,更要知其所以然。


ddl实现方式


5.6 online ddl推出以前,执行ddl主要有两种方式copy方式和inplace方式,inplace方式又称为(fast index creation)。相对于copy方式,inplace方式不拷贝数据,因此较快。但是这种方式仅支持添加、删除索引两种方式,而且与copy方式一样需要全程锁表,实用性不是很强。下面以加索引为例,简单介绍这两种方式的实现流程。


   copy方式


   (1).新建带索引的临时表

   (2).锁原表,禁止DML,允许查询

   (3).将原表数据拷贝到临时表(无排序,一行一行拷贝)

   (4).进行rename,升级字典锁,禁止读写

   (5).完成创建索引操作


   inplace方式


   (1).新建索引的数据字典

   (2).锁表,禁止DML,允许查询

   (3).读取聚集索引,构造新的索引项,排序并插入新索引

   (4).等待打开当前表的所有只读事务提交

   (5).创建索引结束


online ddl实现


online方式实质也包含了copy和inplace方式,对于不支持online的ddl操作采用copy方式,比如修改列类型,删除主键,修改字符集等,这些操作都会导致记录格式发生变化,无法通过简单的全量+增量的方式实现online;对于inplace方式,mysql内部以“是否修改记录格式”为基准也分为两类,一类需要重建表(重新组织记录),比如optimize table、添加索引、添加/删除列、修改列NULL/NOT NULL属性等;另外一类是只需要修改表的元数据,比如删除索引、修改列名、修改列默认值、修改列自增值等。Mysql将这两类方式分别称为rebuild方式和no-rebuild方式。更多关于哪些DDL是否可以inplace的内容可以参考官方文档:http://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-overview.html。online ddl主要包括3个阶段,prepare阶段,ddl执行阶段,commit阶段,rebuild方式比no-rebuild方式实质多了一个ddl执行阶段,prepare阶段和commit阶段类似。下面将主要介绍ddl执行过程中三个阶段的流程。


Prepare阶段:


创建新的临时frm文件

持有EXCLUSIVE-MDL锁,禁止读写

根据alter类型,确定执行方式(copy,online-rebuild,online-norebuild)

更新数据字典的内存对象

分配row_log对象记录增量

生成新的临时ibd文件


ddl执行阶段:


降级EXCLUSIVE-MDL锁,允许读写

扫描old_table的聚集索引每一条记录rec

遍历新表的聚集索引和二级索引,逐一处理

根据rec构造对应的索引项

将构造索引项插入sort_buffer块

将sort_buffer块插入新的索引

处理ddl执行过程中产生的增量(仅rebuild类型需要)


commit阶段


升级到EXCLUSIVE-MDL锁,禁止读写

重做最后row_log中最后一部分增量

更新innodb的数据字典表

提交事务(刷事务的redo日志)

修改统计信息

rename临时idb文件,frm文件

变更完成  


链接文章

http://www.cnblogs.com/cchust/p/4639397.html