MySQL online ddl原理
背景
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文件
- 变更完成
关键函数堆栈
拷贝数据
row_merge_build_indexes
row_merge_read_clustered_index //拷贝全量
{
遍历老表的聚集索引
row_build //创建一个row
row_merge_buf_add
//将row加入到sort_buffer
row_merge_insert_index_tuples //插入到新表(聚集索引+二级索引)
}
row_log_table_apply
//对于rebuild类型,处理增量
{
row_log_table_apply_insert //以insert为例
row_log_table_apply_convert_mrec //将buf项转为tuple
{
插入聚集索引 //
row_ins_clust_index_entry_low
插入二级索引
// row_ins_sec_index_entry_low
}
}
对于添加索引的操作,由于不需要修改聚集索引,因此处理增量调用的是另外一套接口
row_log_apply->row_log_apply_ops->row_log_apply_op->row_log_apply_op_low->
修改表数据字典
commit_try_norebuild,commit_try_rebuild
常见的ddl操作
类型 |
并发DML |
算法 |
备注 |
添加/删除索引 |
Yes |
Online(no-rebuild) |
全文索引不支持 |
修改default值 修改列名 修改自增列值 添加/删除外键约束 |
Yes |
Nothing |
仅需要修改元数据 |
添加/删除列 交换列顺序 修改NULL/NOT NULL 修改ROW-FORMAT 添加/修改PK Optimize table |
Yes |
Online(rebuild) |
由于记录格式改变,需要重建表 |
修改列类型 删除PK 转换字符集 添加全文索引 |
No |
Copy |
需要锁表,不支持online |
若干问题
1.如何实现数据完整性
使用online ddl后,用户心中一定有一个疑问,一边做ddl,一边做dml,表中的数据不会乱吗?这里面关键部件是row_log。row_log记录了ddl变更过程中新产生的dml操作,并在ddl执行的最后将其应用到新的表中,保证数据完整性。
2.online与数据一致性如何兼得
实际上,online ddl并非整个过程都是online,在prepare阶段和commit阶段都会持有MDL-Exclusive锁,禁止读写;而在整个ddl执行阶段,允许读写。由于prepare和commit阶段相对于ddl执行阶段时间特别短,因此基本可以认为是全程online的。Prepare阶段和commit阶段的禁止读写,主要是为了保证数据一致性。Prepare阶段需要生成row_log对象和修改内存的字典;Commit阶段,禁止读写后,重做最后一部分增量,然后提交,保证数据一致。
3.如何实现server层和innodb层一致性
在prepare阶段,server层会生成一个临时的frm文件,里面包含了新表的格式;innodb层生成了临时的ibd文件(rebuild方式);在ddl执行阶段,将数据从原表拷贝到临时ibd文件,并且将row_log增量应用到临时ibd文件;在commit阶段,innodb层修改表的数据字典,然后提交;最后innodb层和mysql层面分别重命名frm和idb文件。
4.对innodb表做ddl过程中异常了,为啥再次做ddl报#sql-xxx already exists
这个错误是什么鬼?这个表#sql-xxx实质是做ddl产生的临时表,ddl异常退出后(比如进程被kill,或者机器异常掉电等),临时文件没有清理。再次执行时,会创建同名的#sql-xxx临时文件,从而导致报错。这里的xxx与table-id强相关,如果是这样,我们把这个讨厌的#sql-xxx临时文件删掉如何呢?再次重做ddl发现还是报同样的错误。这主要原因是,这个临时表信息在innodb的数据字典有残留,通过查询数据字典视图information_schema.innodb_sys_tables,可以发现存在一条#sql-xxx的表记录。
深层次原因:ddl整个过程不是原子的,prepare过程中会新建frm文件,ibd文件,并更新数据字典;然后再进行拷贝全量+重放增量操作;最后再rename frm文件,idb文件,并修改数据字典。由于整个过程涉及到server层和innodb层,并不是一个大事务(每次改数据字典都是单独一个事务),所以执行过程中如果异常终止,就会导致临时表数据字典残留在系统表内。
影响:虽然临时表信息残留在数据字典内,但不影响用户后续操作。
解决方法:由于临时表与table-id强相关,如何改变table-id是我们需要做的,但表又不能被修改,table-id改变不了。这就成了一个悖论,要做ddl,需要改变table-id;要改变table-id,又需要通过ddl操作。查看源码后发现,对于online ddl,临时表名依赖于变更表的table-id(比如#sql-ib79,79就是变更表的table-id),而对于copy类型(非online)的ddl,临时表名则不依赖于table-id(由mysqld进程号+连接会话号产生,比如sql-604d_2,604d是mysqld进程号,2是会话号)。因此,我们通过copy类型的ddl,就可以产生表名不一样的临时表了,也就可以完成ddl任务了。比如:alter table test_log add column c88 int, ALGORITHM=copy;
其它:ddl异常结束,会导致重做ddl失败。如果做ddl过程中,kill query,这个时候ddl也会退出,但退出前会做好善后工作,清理数据字典,因此再次做ddl不会存在问题。
参考文档
MySQL online ddl原理的更多相关文章
- 详谈 MySQL Online DDL
作为一名DBA,对数据库进行DDL操作非常多,如添加索引,添加字段等等.对于MySQL数据库,DDL支持的并不是很好,一不留心就导致了全表被锁,经常搞得刚入门小伙伴很郁闷又无辜,不是说MySQL支持O ...
- 【科普】MySQL中DDL操作背后的并发原理
一. 简介 DQL:指数据库中的查询(select)操作. DML:指数据库中的插入(insert).更新(update).删除(delete)等行数据变更操作. DDL:指数据库中加列(add co ...
- 详谈 MySQL 8.0 原子 DDL 原理
柯煜昌 青云科技研发顾问级工程师 目前从事 RadonDB 容器化研发,华中科技大学研究生毕业,有多年的数据库内核开发经验. 文章字数 3800+,阅读时间 15 分钟 背景 MySQL 5.7 的字 ...
- mysql online ddl
大家知道,互联网业务是典型的OLTP(online transaction process)应用,这种应用访问数据库的特点是大量的短事务高并发运行.因此任何限制高并发的动作都是不可接受的,甚至 ...
- MySQL在线DDL gh-ost 使用说明
背景: 作为一个DBA,大表的DDL的变更大部分都是使用Percona的pt-online-schema-change,本文说明下另一种工具gh-ost的使用:不依赖于触发器,是因为他是通过模拟从库, ...
- MySQL在线DDL工具 gh-ost
一.简介 gh-ost基于 golang 语言,是 github 开源的一个 DDL 工具,是 GitHub's Online Schema Transmogrifier/Transfigurator ...
- MYSQL索引结构原理、性能分析与优化
[转]MYSQL索引结构原理.性能分析与优化 第一部分:基础知识 索引 官方介绍索引是帮助MySQL高效获取数据的数据结构.笔者理解索引相当于一本书的目录,通过目录就知道要的资料在哪里, 不用一页一页 ...
- [资料收集]MySQL在线DDL工具pt-online-schema-change
MySQL在线DDL工具pt-online-schema-change pt-online-schema-change使用说明(未完待续) 官网
- MySQL主从同步原理 部署【转】
一.主从的作用:1.可以当做一种备份方式2.用来实现读写分离,缓解一个数据库的压力二.MySQL主从备份原理master 上提供binlog ,slave 通过 I/O线程从 master拿取 bin ...
随机推荐
- iOS阶段学习第16天笔记(Category-NSSet-SEL-NSIndexSet 操作)
iOS学习(OC语言)知识点整理 一.NSSet.NSMutableSet集合的介绍 1)NSSet.NSMutableSet集合,元素是无序的,不能有重复的值. 2)用实例方法创建一个不可变集合对象 ...
- csharp:using OpenXml SDK 2.0 and ClosedXML read excel file
https://openxmlexporttoexcel.codeplex.com/ http://referencesource.microsoft.com/ 引用: using System; u ...
- Scalaz(23)- 泛函数据结构: Zipper-游标定位
外面沙尘滚滚一直向北去了,意识到年关到了,码农们都回乡过年去了,而我却留在这里玩弄“拉链”.不要想歪了,我说的不是裤裆拉链而是scalaz Zipper,一种泛函数据结构游标(cursor).在函数式 ...
- UVA 10090 Marbles 扩展欧几里得
来源:http://www.cnblogs.com/zxhl/p/5106678.html 大致题意:给你n个球,给你两种盒子.第一种盒子每个盒子c1美元,可以恰好装n1个球:第二种盒子每个盒子c2元 ...
- Koala – 开源的前端预处理器语言图形编译工具
koala 是一个前端预处理器语言图形编译工具,支持 Less.Sass.Compass.CoffeeScript,帮助 Web 开发者更高效地使用它们进行开发.跨平台运行,完美兼容 Windows. ...
- Chance – 功能强大的 JavaScript 随机数生成类库
Chance 是一个基于 JavaScript 的随机数工具类.可以生成随机数字,名称,地址,域名,邮箱,时间等等,几乎网站中使用的任何形式的内容都能够生成.这个随机数工具可以帮助减少单调的测试数据编 ...
- JavaScript入门篇QA总结
Q1:JS可以放在哪个位置?A1:1.放在<head>标签中,用<script type="text/javascript"></script> ...
- 【iScroll源码学习03】iScroll事件机制与滚动条的实现
前言 想不到又到周末了,周末的时间要抓紧学习才行,前几天我们学习了iScroll几点基础知识: 1. [iScroll源码学习02]分解iScroll三个核心事件点 2. [iScroll源码学习01 ...
- 首届Autodesk编程马拉松(Hackathon)开始报名啦 -- 6.14~15 上海
欢迎报名参加Autodesk 首届编程马拉松 ( Hackathon ) 活动 首届Autodesk编程马拉松(Hackathon)活动即将在Autodesk公司中国研究院(上海)举办.本次编程马 ...
- 【转】C++标准库和标准模板库
C++强大的功能来源于其丰富的类库及库函数资源.C++标准库的内容总共在50个标准头文件中定义.在C++开发中,要尽可能地利用标准库完成.这样做的直接好处包括:(1)成本:已经作为标准提供,何苦再花费 ...