这个部分也是日常开发中很常见的问题。在数据量在的情况下,我们修改表结构,会发生什么?
DDL
DDL定义了数据在数据库中的结构、关系以及权限等。比如 CREATE,ALTER,DROP 这些
既然是定义啊,其实 DDL 的作用就是改变表结构,那么问题来了:表结构在 InnoDB 下是什么样的?
- 数据 ==> 索引即数据,
Innodb中存储的数据其实就是按照聚簇索引排列的 - 每一行数据依次排列
第一个问题:我现在要加一列?
- 要在每一行都加一列
- 修改表空间中的元数据
- 重建索引
等同于我需要重建一整张表,这个可想而之时非常高昂的!
Scheme 变更
说几个我们可以想到的方案:
- 直接
alter table,数据少并不会造成太长时间的锁表 - 停机就完事~~~。停机升级~~~。【是不是juejin以前干过这种事】
- 在线淦
最后一个其实才是我们日常最多遇到的情况。最核心的问题是:
- 用户数据在业务运行中也在产生,这部分数据一定要保存
- 操作不能对现有的数据产生影响
所以可以想到的做法,也是早期 mysql 的做法是:
DDL 操作(如创建索引等)通常都需要对数据表加锁,操作过程中 DML 操作都会被阻塞,影响正常业务。
既然新来的数据会影响,那干脆就直接拒绝掉,等我重建完再来接受请求。
Online DDL
MySQL 5.6 开始支持 Online DDL,可以在执行 DDL 操作的同时,不影响 DML 的正常执行,线上直接执行 DDL 操作对用户基本无感知(部分操作对性能有影响)。
在 ALTER TABLE 语句中,支持通过 ALGORITHM 和 LOCK 语句来实现 Online DDL:
ALGORITHM- 控制 DDL 操作如何执行,使用哪个算法LOCK- 控制在执行 DDL 时允许对表加锁的级别
ALTER TABLE tab ADD COLUMN c varchar(50), ALGORITHM=INPLACE, LOCK=NONE;
算法有如下这些:
DEFAULT:默认算法,自动使用可用的最高效的算法COPY:最原始的方式,所有的存储引擎都支持,不使用 Online DDL,操作时会创建临时表,执行全表拷贝和重建,过程中会写入 Redo Log 和大量的 Undo Log,需要添加读锁,非常低效INPLACE:尽可能避免表拷贝和重建,由存储引擎决定如何实现,有些操作是可以立即生效的(比如重命名列,改变列的默认值等),但有些操作依然需要全表或者部分表的拷贝和重建(比如添加删除列、添加主键、改变列为 NULL 等)NOCOPY:避免聚簇索引(主键索引)的重建造成全表重建INSTANT:所有涉及到表拷贝和重建的操作都会被禁止
运行过程:
整个 Online DDL 执行过程:
- 建立一个临时文件,扫描表的全部数据页
- 使用当前表的记录生成一个 B+ 🌲,存储到临时文件中
- 生成临时文件的过程中,将所有对当前表的操作记录在一个日志文件(row log)中
- 临时文件生成后,将日志文件中的操作应用到临时文件,得到一个逻辑数据上与表A相同的数据文件
- 用临时文件替换表A的数据文件。
工具
介绍一个平时我们日常用的最多的:
pt-online-schema-change
有一说一,percona 这家公司真的NB,生产了很多mysql运维的toolkit,强烈推荐大家使用