MySQL Online DDL详解:从历史演进到原理及使用

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: MySQL Online DDL详解:从历史演进到原理及使用

一、Online DDL的发展历史

MySQL Online DDL 功能从 5.6 版本开始正式引入,发展到现在的 8.0 版本,经历了多次的调整和完善。本文主要就 Online DDL 的发展过程,以及各版本的区别进行总结。其实早在 MySQL 5.5 版本中就加入了 INPLACE DDL 方式,但是因为实现的问题,依然会阻塞 INSERT、UPDATE、DELETE 操作,这也是 MySQL 早期版本长期被吐槽的原因之一。


在 MySQL 5.6 中,官方开始支持更多的 ALTER TABLE 类型操作来避免数据拷贝,同时支持了在线上 DDL 的过程中不阻塞 DML 操作,真正意义上的实现了 Online DDL。然而并不是所有的 DDL 操作都支持在线操作,后面会附上 MySQL 官方文档对于 DDL 操作的总结。


到了 MySQL 5.7,在 5.6 的基础上又增加了一些新的特性,比如:增加了重命名索引支持,支持了数值类型长度的增大和减小,支持了 VARCHAR 类型的在线增大等。但是基本的实现逻辑和限制条件相比 5.6 并没有大的变化。


MySQL 8.0 对 DDL 的实现重新进行了设计,其中一个最大的改进是 DDL 操作支持了原子特性。另外,Online DDL 的 ALGORITHM 参数增加了一个新的选项:INSTANT,只需修改数据字典中的元数据,无需拷贝数据也无需重建表,同样也无需加排他 MDL 锁,原表数据也不受影响。整个 DDL 过程几乎是瞬间完成的,也不会阻塞 DML。

二、Online DDL的算法

了解 Online DDL 先了解一下之前 DDL 的 2 种算法 copy 和 inplace。

Copy算法
  1. 按照原表定义创建一个新的临时表
  2. 对原表加写锁(禁止 DML,允许 select)
  3. 步骤 1)建立的临时表执行 DDL
  4. 将原表中的数据 copy 到临时表
  5. 释放原表的写锁
  6. 将原表删除,并将临时表重命名为原表

可见,采用 copy 方式期间需要锁表,禁止 DML,因此是非 Online 的。比如:删除主键、修改列类型、修改字符集,这些操作会导致行记录格式发生变化(无法通过全量 + 增量实现 Online)。

Inplace算法

在原表上进行更改,不需要生成临时表,不需要进行数据 copy 的过程。根据是否变更行记录格式,分为两类:

  1. rebuild:需要重建表(重新组织聚簇索引)。比如 optimize table、添加索引、添加/删除列、修改列 NULL/NOT NULL 属性等;
  2. no-rebuild:不需要重建表,只需要修改表的元数据,比如删除索引、修改列名、修改列默认值、修改列自增值等。

对于 rebuild 方式实现 Online 是通过缓存 DDL 期间的 DML,待 DDL 完成之后,将 DML 应用到表上来实现的。

说明:

  1. 在 copy 数据到新表期间,在原表上是加的 MDL 读锁(允许 DML,禁止 DDL)
  2. 在应用增量期间对原表加 MDL 写锁(禁止 DML 和 DDL)
  3. 根据表A重建出来的数据是放在 tmp_file 里的,这个临时文件是 InnoDB 在内部创建出来的,整个 DDL 过程都在 InnoDB 内部完成。对于 server 层来说,没有把数据挪动到临时表,是一个原地操作,这就是“inplace”名称的来源。

MySQL中,表级别的锁有2种

一种是我们通常说的表锁,由InnoDB引擎实现,如lock tables …

read/write,表锁影响较大,不常用。另一种表级别的锁是MDL( metadata lock

),由Server层实现,MDL我们不显式使用,是在访问一个表时由数据库自动加的,对表记录增删改查时,加MDL读锁;对表结构进行变更时,加MDL写锁。MDL锁,读读不互斥,读写、写写互斥。

哪些常用操作“锁表”

创建二级索引(二级索引是指除主键索引之外的索引)、删除索引、重命名索引、改变索引类型——不“锁表”。

添加字段、删除字段、重命名字段、调整字段顺序、设置字段默认值、删除字段默认值、修改auto-increment值、调整字段允许NULL、调整字段不允许NULL

—— 不“锁表”。

扩展Varchar字段大小——不“锁表”。

更改字段数据类型,如varchar改成text——“锁表”

三、Online DDL过程中的锁

默认情况下,MySQL就是支持online的DDL操作的,在online的DDL语句执行的过程中,MySQL会尽量少使用锁的限制,我们不需要特殊的操作来启用它。

MySQL在选择的时候,尽量少使用锁,但是不排除它会选择使用锁。而如果我担心它选择了锁而导致我们的表不能读也不能写,显然这不是我们想要的结果,我们希望:如果选择了锁就不要执行,直接退出执行;如果没有选择锁就执行。想要达到我们希望的这个效果,该怎么做呢?

可以在执行我们的online DDL语句的时候,使用ALGORITHM和LOCK关键字,这两个关键字在我们的DDL语句的最后面,用逗号隔开即可。示例如下:

ALTER TABLE tbl_name ADD COLUMN col_name col_type, ALGORITHM=INPLACE, LOCK=NONE;


ALGORITHM的选项
  • INPLACE:替换:直接在原表上面执行DDL的操作。
  • COPY:复制:使用一种临时表的方式,克隆出一个临时表,在临时表上执行DDL,然后再把数据导入到临时表中,在重命名等。这期间需要多出一倍的磁盘空间来支撑这样的 操作。执行期间,表不允许DML的操作。
  • DEFAULT:默认方式,有MySQL自己选择,优先使用INPLACE的方式。
LOCK的选项
  • SHARE:共享锁,执行DDL的表可以读,但是不可以写。
  • NONE:没有任何限制,执行DDL的表可读可写。
  • EXCLUSIVE:排它锁,执行DDL的表不可以读,也不可以写。
  • DEFAULT:默认值,也就是在DDL语句中不指定LOCK子句的时候使用的默认值。如果指定LOCK的值为DEFAULT,那就是交给MySQL子句去觉得锁还是不锁表。不建议使用,如果你确定你的DDL语句不会锁表,你可以不指定lock或者指定它的值为default,否则建议指定它的锁类型。

执行DDL操作时,ALGORITHM选项可以不指定,这时候MySQL按照INSTANT、INPLACE、COPY的顺序自动选择合适的模式。也可以指定ALGORITHM=DEFAULT,也是同样的效果。如果指定了ALGORITHM选项,但不支持的话,会直接报错。

注意:

在执行OnlineDDL之前,要在非业务高峰期去执行,并要确认待执行的表上面没有未提交的事务、锁等信息。可以通过如下的SQL语句查看是否有事务和锁等信息。

select * from information_schema.innodb_locks;
select * from information_schema.innodb_trx;
select * from information_schema.innodb_lock_waits;
select * from information_schema.processlist;

四、理解DDL操作的需求和挑战

DDL操作涉及对数据库表结构的修改,例如添加/删除列、修改列定义、添加/删除索引等。在以往的版本中,执行这些DDL操作时需要锁定整个表,对数据库的可用性产生了负面影响。因此,实现在线DDL成为了提高系统灵活性和性能的重要需求。

五、MySQL 5.7的在线DDL功能特点

MySQL 5.7通过InnoDB存储引擎实现了在线DDL功能的改进。以下是该功能的主要特点:

  • 支持添加辅助索引:可以在运行中的表上添加辅助索引,而不会对整个表进行锁定。
  • 支持修改列定义:可以在线修改列的数据类型、长度等定义。
  • 支持修改字符集和排序规则:可以在线修改表的字符集和排序规则设置。
  • 支持重命名列:可以在不影响正在进行的读写操作的情况下,对表中的列进行重命名。

六、实现原理和优化

在线DDL功能的实现涉及以下关键步骤和优化:

  • 1 创建临时表:通过创建临时表来存储将要进行的DDL操作所需的新结构。这样,旧表仍然可用于读写操作。
  • 2 数据复制和同步:将旧表中的数据逐步复制到临时表中,并保持旧表数据与临时表数据的同步。这一过程确保了数据在DDL操作期间的完整性和一致性。
  • 3 变更捕获和重放:通过使用日志和重做日志等机制,捕获在执行DDL操作期间发生的数据变更,并将其重放到临时表中。这确保了DDL操作完成后数据的一致性。
  • 4 最终切换:当DDL操作完成时,数据库引擎将在适当的时机切换到临时表,使其成为新的表结构,并且对新表进行后续的读写操作。

七、使用限制和注意事项

尽管MySQL 5.7的在线DDL功能提供了一种近似在线的体验,但仍然有一些限制和注意事项:

  • 并非所有DDL操作都支持在线执行,某些操作仍然需要锁定整个表。
  • 在进行DDL操作期间,可能会占用较多的系统资源,因此在高负载时应谨慎使用。
  • 进行在线DDL操作时,需要对操作进行充分的评估和测试,以确保数据的完整性和一致性。

八、各版本支持的详细情况

本文数据全部来自 MySQL 官方文档,此处进行一个集中的整理和总结:

https://dev.mysql.com/doc/refman/5.6/en/innodb-online-ddl-operations.html

https://dev.mysql.com/doc/refman/5.7/en/innodb-online-ddl-operations.html

https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html

九、 DDL 的执行模式

结合上面的表格,对 MySQL 当前 DDL 的执行模式总结如下:

1. INSTANT DDL 是 MySQL 8.0 引入的新功能,当前支持的范围较小,包括:

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

2. 在执行 DDL 操作时,MySQL 内部对于 ALGORITHM 的选择策略:

如果用户显式指定了 ALGORITHM,那么使用用户指定的选项;

如果用户未指定,那么如果该操作支持 INPLACE 则优先选择 INPLACE,否则选择 COPY;

当前不支持 INPLACE 的操作主要有:

  • 删除主键
  • 修改列数据类型
  • 修改表字符集

3. 我们常说的 Online DDL,其实是从 DML 操作的角度描述的,如果 DDL 操作不阻塞 DML 操作,那么这个 DDL 就是 Online 的。当前非 Online 的 DDL 其实已经比较少了,主要有:

  • 新增全文索引
  • 新增空间索引
  • 删除主键
  • 修改列数据类型
  • 指定表字符集
  • 修改表字符集

更多详细的示例请参考上面的官方文档的地址。


十、探讨几个问题

最后讨论几个非常容易混淆的问题:

  • Online DDL 不会锁表,可以随意的执行。
  • 支持 INPLACE 算法的 DDL 一定是 Online 的。
  • 对于支持 INPLACE 算法的 DDL,DDL 操作是原地修改数据,不需要额外的数据空间。
Q1: Online DDL 会不会锁表

Online DDL 会不会锁表?要回答这个问题,首先要明确“锁表”的含义。很多 MySQL 用户经常在表无法正常的进行 DML 时就觉得是锁表了,这种说法其实过于宽泛,实际上能够影响 DML 操作的锁至少包括以下几种(默认为 InnoDB 表):

MDL 锁
表锁
行锁
GAP 锁

其中除了 MDL 锁是在 Server 层加的之外,其它三种都是在 InnoDB 层加的。具体的加锁逻辑不在此进行展开,但是需要明确一点:所有的操作(不管是 DDL 还是 DML 还是查询语句)都需要先拿 Server 层的 MDL 锁,然后再去拿 InnoDB 层的某个需要的锁。

一个 DDL 的基本过程是这样的:

  • 首选,在开始进行 DDL 时,需要拿到对应表的 MDL X 锁,然后进行一系列的准备工作;
  • 然后将 MDL X 锁降级为 MDL S 锁,进行真正的 DDL 操作;
  • 最后再次将 MDL S 锁升级为 MDL X 锁,完成 DDL 操作,释放 MDL 锁;

所以在真正执行 DDL 操作期间,确实是不会“锁表”的,但是如果在第一阶段拿 MDL X 锁时无法正常获取,那就可能真的会“锁表了”。一个简单的例子如下:

# session 1
select sleep(500) from mytest.t1;

# session 2
optimize table mytest.t1;

# session 3
select * from mytest.t1;

session 1 模拟了一个慢查询,然后 session 2 开始进行 DDL 操作,无法拿到 MDL X 锁,处于等到中。此时 session 3 需要执行一个查询,发现无法执行。实际上,在 session 1 结束前,表 t1 的所有操作都无法进行了,也可以说表 t1 “锁表”了。MySQL 5.7/8.0 可以在开启 performance_schema 的情

况下直接查询 metadata_locks 表。阿里云 RDS 5.6 版本新增了 I_S.MDL_INFO 表,提供 MDL 的查询。

MySQL [performance_schema]> select * from metadata_locks where OBJECT_NAME = 't1';
+-------------+---------------+-------------+-------------+-----------------------+----------------------+---------------+-------------+-------------------+-----------------+----------------+
| OBJECT_TYPE | OBJECT_SCHEMA | OBJECT_NAME | COLUMN_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE            | LOCK_DURATION | LOCK_STATUS | SOURCE            | OWNER_THREAD_ID | OWNER_EVENT_ID |
+-------------+---------------+-------------+-------------+-----------------------+----------------------+---------------+-------------+-------------------+-----------------+----------------+
| TABLE       | mytest        | t1          | NULL        |       140730442220576 | SHARED_READ          | TRANSACTION   | GRANTED     | sql_parse.cc:5916 |            1083 |             24 |
| TABLE       | mytest        | t1          | NULL        |       140730576178368 | SHARED_NO_READ_WRITE | TRANSACTION   | PENDING     | sql_parse.cc:5916 |            1091 |              3 |
| TABLE       | mytest        | t1          | NULL        |       140730374843168 | SHARED_READ          | TRANSACTION   | PENDING     | sql_parse.cc:5916 |            1092 |              3 |
+-------------+---------------+-------------+-------------+-----------------------+----------------------+---------------+-------------+-------------------+-----------------+----------------+
3 rows in set (0.00 sec)

明确了上面的概念之后,再回到我们的问题,Online DDL 是不是不锁表?如果非要回答,那么只能说,Online DDL 并不是绝对安全,更不是可以随意的执行。线上操作还是需要在业务低峰期谨慎操作。

Q2: 支持 INPLACE 算法的 DDL 一定是 Online 的

从概念上来说,INPLACE 和 Online 是两个不同维度的事情。COPY 和 INPLACE 指的是 DDL 内部的执行逻辑,可以简单的理解成:COPY 是在 Server 层的操作,INPLACE 是在 InnoDB 层的操作。而用户更加关心 Online 与否,通常只与一个问题有关:是否允许并发 DML。

两个基本结论:

  • COPY 算法执行的 DDL 肯定不是 Online 的;
  • INPLACE 算法执行的 DDL 不一定是 Online 的;
Q3: INPLACE DDL 需不需要额外的数据空间

前面我们提到过,MySQL 内部对于 DDL 的 ALGORITHM 有两种选择:INPLACE 和 COPY(8.0 新增了 INSTANT,但是使用范围较小)。COPY 算法理解起来相对简单一点:创建一张临时表,然后将原表的数据拷贝到临时表中,最后再用临时表替换原表。对于上面的步骤,由于需要将原表的数据拷贝到临时表中,所以肯定需要消耗额外的数据空间。

那么对于支持 INPLACE 算法的 DDL,是不是不需要额外的数据空间?

答案是:需要。其实之所以会问这个问题,还是因为对 INPLACE 本身的理解出现了偏差。简单来说:INPLACE 描述的是表,而不是数据文件。只要不创建临时表,那么都是 INPLACE 的。

实际上,很多 INPLACE DDL 都会重建表(会创建临时数据文件),所以都会需要额外的数据空间,例如:

  • 增加主键
  • 重建主键
  • 新增列(8.0 支持 INSTANT DDL,不需要)
  • 删除列
  • 调整列顺序
  • 删除列默认值
  • 增加列默认值
  • 修改表的 ROW_FORMAT
  • OPTIMIZE 表


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
13天前
|
存储 关系型数据库 MySQL
MySQL主从复制原理和使用
本文介绍了MySQL主从复制的基本概念、原理及其实现方法,详细讲解了一主两从的架构设计,以及三种常见的复制模式(全同步、异步、半同步)的特点与适用场景。此外,文章还提供了Spring Boot环境下配置主从复制的具体代码示例,包括数据源配置、上下文切换、路由实现及切面编程等内容,帮助读者理解如何在实际项目中实现数据库的读写分离。
MySQL主从复制原理和使用
|
30天前
|
缓存 算法 关系型数据库
Mysql(3)—数据库相关概念及工作原理
数据库是一个以某种有组织的方式存储的数据集合。它通常包括一个或多个不同的主题领域或用途的数据表。
46 5
Mysql(3)—数据库相关概念及工作原理
|
8天前
|
SQL 关系型数据库 MySQL
|
29天前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1607 14
|
13天前
|
SQL 关系型数据库 MySQL
Mysql中搭建主从复制原理和配置
主从复制在数据库管理中广泛应用,主要优点包括提高性能、实现高可用性、数据备份及灾难恢复。通过读写分离、从服务器接管、实时备份和地理分布等机制,有效增强系统的稳定性和数据安全性。主从复制涉及I/O线程和SQL线程,前者负责日志传输,后者负责日志应用,确保数据同步。配置过程中需开启二进制日志、设置唯一服务器ID,并创建复制用户,通过CHANGE MASTER TO命令配置从服务器连接主服务器,实现数据同步。实验部分展示了如何在两台CentOS 7服务器上配置MySQL 5.7主从复制,包括关闭防火墙、配置静态IP、设置域名解析、配置主从服务器、启动复制及验证同步效果。
Mysql中搭建主从复制原理和配置
|
22天前
|
SQL 关系型数据库 MySQL
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
尼恩,一位40岁的资深架构师,通过其丰富的经验和深厚的技術功底,为众多读者提供了宝贵的面试指导和技术分享。在他的读者交流群中,许多小伙伴获得了来自一线互联网企业的面试机会,并成功应对了诸如事务ACID特性实现、MVCC等相关面试题。尼恩特别整理了这些常见面试题的系统化解答,形成了《MVCC 学习圣经:一次穿透MYSQL MVCC》PDF文档,旨在帮助大家在面试中展示出扎实的技术功底,提高面试成功率。此外,他还编写了《尼恩Java面试宝典》等资料,涵盖了大量面试题和答案,帮助读者全面提升技术面试的表现。这些资料不仅内容详实,而且持续更新,是求职者备战技术面试的宝贵资源。
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
|
1月前
|
SQL 关系型数据库 MySQL
MySQL 更新1000万条数据和DDL执行时间分析
MySQL 更新1000万条数据和DDL执行时间分析
77 4
|
1月前
|
存储 SQL 关系型数据库
mysql中主键索引和联合索引的原理与区别
本文详细介绍了MySQL中的主键索引和联合索引原理及其区别。主键索引按主键值排序,叶节点仅存储数据区,而索引页则存储索引和指向数据域的指针。联合索引由多个字段组成,遵循最左前缀原则,可提高查询效率。文章还探讨了索引扫描原理、索引失效情况及设计原则,并对比了InnoDB与MyISAM存储引擎中聚簇索引和非聚簇索引的特点。对于优化MySQL性能具有参考价值。
|
3月前
|
SQL 关系型数据库 MySQL
说一下MySQL主从复制的原理?
【8月更文挑战第24天】说一下MySQL主从复制的原理?
59 0
|
23天前
|
存储 关系型数据库 MySQL
Mysql(4)—数据库索引
数据库索引是用于提高数据检索效率的数据结构,类似于书籍中的索引。它允许用户快速找到数据,而无需扫描整个表。MySQL中的索引可以显著提升查询速度,使数据库操作更加高效。索引的发展经历了从无索引、简单索引到B-树、哈希索引、位图索引、全文索引等多个阶段。
56 3
Mysql(4)—数据库索引