MySQL 8.0 Online DDL快速加列的相关总结


Posted in MySQL onJune 02, 2021

问题描述

前几天同事问了我一个问题:业务A从MySQL迁移到MongoDB的原因是什么?

说实话,这个问题还真不好回答,为什么要迁移,一定是遇到了某种瓶颈,可能是数据量也可能是数据类型等,于是我咨询了一下业务,最终得到了答案:这个业务中的某些表,要频繁的加字段。mongodb中加字段的成本几乎没有,而MySQL低版本中加字段的成本还是挺高的。

那么常用的MySQL添加字段的方法有哪些呢?这里我简单列举一下:

1、percona的pt-osc工具

2、github开源项目gh-ost工具

3、MySQL原生Online DDL

MySQL Online DDL加列的历史方法

01 Copy方法

MySQL5.5版本及之前的加列方法:Copy

它的执行示意图如下:

MySQL 8.0 Online DDL快速加列的相关总结

我们有一个原表A,只包含1个字段,它包含1、2、4、6这几条记录,当我们使用Copy算法加列时:

1、创建了一个新的表tmp-A,新表包含2个字段,

2、然后我们把表A的数据全部逐行拷贝到tmp-A这个新表里面,

3、然后用tmp-A表和A表做个交换,

    这样,我们的新表就包含2个字段了。同时需要注意,新表中的数据记录比原表更加紧凑了。原表中可能由于删除了3和5两条记录,使得表中间留下了空洞,或者叫空间碎片。

    可以看到,Copy算法需要拷贝一遍数据,需要额外的存储空间来存储tmp-A这个临时表。另外,在拷贝数据的过程中,表A的写入操作会丢失,也就是说,表A在alter table的过程中不能有数据更新。这可能是一个致命的缺点。

02 Inplace方法

MySQL5.6版本开始引入Online DDL,这个功能使得上面的过程变成了下面这样:

MySQL 8.0 Online DDL快速加列的相关总结

 它的过程和上面的Copy算法有些不同:

1、Online DDL过程中,从表A提取B+树,并存储到一个中间文件tmp-file,而不是中间表tmp-A

2、步骤1执行过程中,对表A的写入,都会记录到row log中

3、步骤1执行完毕后,对tmp-file应用所有的row log,得到一个与表A数据相同的数据文件

4、利用数据文件tmp-file替换表A的数据文件即可。

    这个过程中,由于row log的存在,使得在整个该表过程中,表A是可以进行增删改查的操作的,因为这些操作不会丢失。这也就是为什么把这个过程叫做Online DDL的原因。

    另外,这里需要解释下,Copy算法中生成的tmp-A临时表是在Server层面创建的,而上述Online DDL操作中的tmp-file是在插件式存储引擎Innodb内部生成的,我们把这种在Innodb内部完成的变更操作,称之为Inplace(中文表示原地),也就是不需要将数据挪动到"server层的临时表"。

MySQL8.0.12 引入的Instant方法

    MySQL8.0.12版本引入了Instant的方法,它让加列变得更加简单。instant算法添加列时不再需要 rebuild 整个表,只需要在表的 metadata 中记录新增列的基本信息即可。

    我们来看它的优势,首先我们创建一个表t1,并插入26w条数据,然后分别添加数据列col_1,col_2,col_3,并显示指定加列的算法为copy、inplace、和instant,结果如下:

[test] 23:42:45> select count(1) from t1;
 +----------+
 | count(1) |
 +----------+
 |   262144 |
 +----------+
 1 row in set (0.06 sec)
 
方案一:copy
[test] 23:43:29> alter table t1 add col_1 int,algorithm=copy;  
Query OK, 262144 rows affected (1.48 sec)
Records: 262144  Duplicates: 0  Warnings: 0

方案二:inplace
[test] 23:43:46> alter table t1 add col_2 int,algorithm=inplace; 
Query OK, 0 rows affected (0.58 sec)
Records: 0  Duplicates: 0  Warnings: 0

方案三:instant
[test] 23:44:08> alter table t1 add col_3 int,algorithm=instant; 
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

m5480:mysqlha_common@10.41.28.124 [test] 23:44:14> show create table t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(10) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `age` int DEFAULT NULL,
  `score` int DEFAULT NULL,
  `col_1` int DEFAULT NULL,
  `col_2` int DEFAULT NULL,
  `col_3` int DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_sco` (`score`)
) ENGINE=InnoDB AUTO_INCREMENT=458730 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
1 row in set (0.01 sec)

   从结果不难看出,执行时间上:

copy> inplace > instant

与此同时,copy算法的受影响行数是全部表,而inplace和instant的算法影响的行数都是0,说明他们是Online DDL操作。 

    最后,我们还可以通过下面的方法查看instant列的信息:

[test] 23:53:01> SELECT * FROM information_schema.innodb_tables where name like 'test/t1'\G
 *************************** 1. row ***************************
      TABLE_ID: 1079
          NAME: test/t1
          FLAG: 33
        N_COLS: 10
         SPACE: 22
    ROW_FORMAT: Dynamic
 ZIP_PAGE_SIZE: 0
   SPACE_TYPE: Single
 INSTANT_COLS: 6
1 row in set (0.00 sec)

    可以看到,test.t1这个表的instant列序号是6,代表它是这个表的第7个列(列编号从0开始)。

    当然,instant算法不支持删除普通列、无法设置列的顺序、还有一些其他的限制,详情可以查看官方文档:https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html

    但这些限制并不影响它成为一个优秀的DDL功能。 相信通过MySQL版本的不断迭代,在后面的版本中,有更多的变更操作可以用到instant这种高效的算法。

以上就是MySQL 8.0 Online DDL快速加列的相关总结的详细内容,更多关于MySQL DDL快速加列的资料请关注三水点靠木其它相关文章!

MySQL 相关文章推荐
MySQL基础(二)
Apr 05 MySQL
mysql知识点整理
Apr 05 MySQL
详解MySQL事务的隔离级别与MVCC
Apr 22 MySQL
MySQL时间盲注的五种延时方法实现
May 18 MySQL
MySQL中distinct和count(*)的使用方法比较
May 26 MySQL
分享MySQL常用 内核 Debug 几种常见方法
Mar 17 MySQL
MySQL限制查询和数据排序介绍
Mar 25 MySQL
mysql 索引的数据结构为什么要采用B+树
Apr 26 MySQL
MySQL的prepare使用以及遇到的bug
May 11 MySQL
MySQL解决Navicat设置默认字符串时的报错问题
Jun 16 MySQL
mysql查看表结构的三种方法总结
Jul 07 MySQL
MySQL实现用逗号进行拼接、以逗号进行分割
Dec 24 MySQL
MySQL 常见存储引擎的优劣
Jun 02 #MySQL
Mysql文件存储图文详解
一文读懂navicat for mysql基础知识
Mysql数据库索引面试题(程序员基础技能)
MySQL CHAR和VARCHAR该如何选择
May 31 #MySQL
带你学习MySQL执行计划
May 31 #MySQL
MySQL完整性约束的定义与实例教程
You might like
php在页面中调用fckeditor编辑器的方法
2011/06/10 PHP
yii框架中的Url生产问题小结
2012/01/16 PHP
微信公众平台开发教程③ PHP实现微信公众号支付功能图文详解
2019/04/10 PHP
laravel解决迁移文件一次删除创建字段报错的问题
2019/10/24 PHP
JavaScript 关键字屏蔽实现函数
2009/08/02 Javascript
Javascript 设计模式(二) 闭包
2010/05/26 Javascript
JavaScript与Div对层定位和移动获得坐标的实现代码
2010/09/08 Javascript
jQuery ajax serialize()方法的使用以及常见问题解决
2013/01/27 Javascript
raphael.js绘制中国地图 地图绘制方法
2014/02/12 Javascript
javascript从image转换为base64位编码的String
2014/07/29 Javascript
js判断鼠标左、中、右键哪个被点击的方法
2015/01/27 Javascript
在Javascript中处理数组之toSource()方法的使用
2015/06/09 Javascript
Node.js的Express框架使用上手指南
2016/03/12 Javascript
简单谈谈gulp-changed插件
2017/02/21 Javascript
JS请求servlet功能示例
2017/06/01 Javascript
微信小程序实战篇之购物车的实现代码示例
2017/11/30 Javascript
基于JSONP原理解析(推荐)
2017/12/04 Javascript
Angular4实现图片上传预览路径不安全的问题解决
2017/12/25 Javascript
Vue2.0+Vux搭建一个完整的移动webApp项目的示例
2019/03/19 Javascript
thinkjs微信中控之微信鉴权登陆的实现代码
2019/08/08 Javascript
axios如何取消重复无用的请求详解
2019/12/15 Javascript
JS中作用域以及变量范围分析
2020/07/18 Javascript
[02:54]DOTA2英雄基础教程 撼地者
2014/01/14 DOTA
[01:56]生活中的妖精之七夕特别档
2016/08/09 DOTA
pytyon 带有重复的全排列
2013/08/13 Python
python调用windows api锁定计算机示例
2014/04/17 Python
Python遍历某目录下的所有文件夹与文件路径
2018/03/15 Python
Python中偏函数用法示例
2018/06/07 Python
使用pyinstaller逆向.pyc文件
2019/12/20 Python
使用tensorboard可视化loss和acc的实例
2020/01/21 Python
Python中if有多个条件处理方法
2020/02/26 Python
tensorflow图像裁剪进行数据增强操作
2020/06/30 Python
python源文件的字符编码知识点详解
2021/03/04 Python
荷兰手表网站:Watch2Day
2018/07/02 全球购物
化学专业自荐信
2014/05/28 职场文书
文员转正自我鉴定怎么写
2014/09/29 职场文书