生产环境中,热点表/大表应该如何扩字段呢?

338 阅读5分钟

本周笔者接到一个需求,该需求需要在tbtransreq表中扩充一个字段,而tbtransreq是我们的一个热点表、大表,基本上所有的交易都要涉及到这张表,且这张表有几百万条数据,那么在这样一张表中,扩充一个字段需要如何实现呢?

有的观众朋友说了,加个字段还不简单,直接执行alter命令不就好了,比如:

 alter table tbtransreq add column (age int default 0 comment '年龄');

但是这种方式可能导致我们的tbtransreq长时间无法进行增删改查,影响正常的业务。这是可能有的观众朋友会问,不就是一条简单的DDL,为什么会执行很长时间呢?为什么还会阻塞增删改查呢?

这就得聊一聊Mysql的元数据锁MetaData Lock,简称MDL。其实我们每平时执行一条DML,都要对表加MDL-S锁(共享锁),执行DDL,对表加MDL-X锁(独占锁),这是server层的锁。在mysql5.6之前的版本,新增字段是通过建临时表、复制数据、重命名表名的过程来实现的。由于是一条一条进行复制,如果数据量比较大,耗时会很长。而且在这个期间会对表一直加MDL-X锁,X锁和S锁是互斥的,所以会阻塞DML操作。但是在5.6版本推出新的算法后,就可以极大的解决DDL执行时间长导致阻塞DML的问题,下面我们就来了解下不同的算法背后的执行逻辑到底是怎么样的。

DDL在各个版本中不同算法的执行过程

5.5版本

copy算法:

1、新建和原表结构一致的临时表(需要新建.frm文件和.ibd文件),并在该临时表上进行DDL。

2、对原表加MDL-X锁,不允许DML,只允许查询。

3、逐行数据从原表拷贝到临时表(这个过程最耗时)。

4、拷贝完成后,禁止对原表进行查询,执行rename操作,将临时表名改为原表,删除原表,完成整个DDL操作。

inplace算法: 仅针对索引的创建和删除

其实早在5.5版本中就推出了inplace算法的DDL,但是因为实现的原因,依然会阻塞insert、update、delete语句的执行。

1、新建.frm临时文件

2、对原表加MDL-X锁,不允许DML,只允许查询。

3、按照聚集索引的顺序查询数据,找到需要的索引列数据,进行排序后插入到新的索引页中。

4、禁止对原表进行查询,执行rename操作,替换.frm文件,完成整个DDL操作。

inplace算法和copy算法相比较而言,没有server层面的建表操作, 只需要修改.frm文件和.ibd文件,减少了大量数据拷贝带来的IO开销,减少DDL的整体耗时,减少表对外不可用的时长。但是5.5版本的inplace算法只能用于新增或删除索引,其他的DDL操作,还需要使用copy算法。

5.6版本

Mysql在5.6版本中推出了在线的DDL,即Online DDL。

inplace算法:

5.6版本的inplace算又可以细分为两种。①rebuild,需要重建表(重新组织聚簇索引);②no-rebuild,不需要重建表。

重建表的判断标准为:是否修改行记录格式。比如修改列类型、增删字段会修改行记录格式;删除索引、设置默认值及重命名字段名不会修改记录格式。

inplace分为三个阶段

  • prepare准备

    (1)、创建新的临时.frm文件

    (2)、对原表加MDL-X锁,禁止读写

    (3)、根据alter类型,确定执行算法(copy、inplace的rebuild、inplace的no-rebuild)

    (4)、分配row log文件和新的临时ibd文件空间

  • execute执行

    (1)、如果仅修改元数据,这部分不需要执行其他操作。

    (2)、否则,对原表进行锁降级,加MDL-S锁,允许读写。将原表的ibd文件内容一条条拷贝到新的临时ibd文件中,在此期间执行的DML写入row log文件

  • commit提交

    (1)、对原表进行锁升级,加MDL-X锁,禁止读写

    (2)、重做row log文件中的内容

    (3)、rename新的临时ibd文件和frm文件为原文件名。

    (4)、DDL完成

5.6版本的inplace算法相比copy算法而言,只会在prepare和commit阶段对原表进行短时间的进行读写,在execute的长耗时过程中,是不会阻塞DML请求的,所以5.6版本的inplace可以被称为Online DDL。

8.0版本

8.0版本对DDL操作支持了原子特性。Online DDL的ALGORITHM参数新增了INSTANT,只需修改数据字段中的元数据,无需要拷贝数据和重新建表,也无需加排他MDL锁,原表数据不受影响,整个DDL过程几乎是瞬间完成的。但是当前支持的范围较小,仅包括:

  • 修改二级索引类型
  • 新增列
  • 修改列默认值
  • 修改列ENUM值
  • 重命名表

在实际生产中,我们需要根据Mysql服务器的版本选择对应的算法,并尽可能的在业务低谷执行DDL操作,尽量较少对正常业务的影响。

数据库内核月报链接:www.bookstack.cn/read/aliyun…

一篇讲解较详细的Online DDL文章:www.cnblogs.com/xinysu/p/67…