MySQL的在线模式学习笔记
wptr33 2025-08-03 08:47 24 浏览
什么是在线模式(ONLINE DDL)?
“在线模式 / 离线模式”是 MySQL 专门为 DDL 设计的术语。ONLINE DDL 定义其实就是在执行 DDL 语句时,不会阻塞 DML 语句,那么我们就称这样的 DDL 为ONLINE DDL。
什么是离线模式?
**离线模式** 是指在 MySQL 5.5 及更早版本中执行 DDL 操作时,表会被完全锁定,所有读写操作将被阻塞,直到操作完成。在离线 DDL 执行期间,需要修改的表会被完全锁定,这意味着所有对该表的读写操作都会被阻塞,直到 DDL 操作完成。由于表被锁定,任何依赖该表的应用程序都将无法正常工作,导致服务中断或延迟。对于高并发、7x24小时运行的线上系统而言,这种长时间的停机是不可接受的。
**在线模式** 是 MySQL 5.6 及更高版本引入的 重大改进 ,旨在解决离线模式带来的服务中断问题。它的核心思想是 允许在 DDL 操作进行的同时,对表进行并发的读写操作 ,从而最大程度地保证数据库的可用性。
#技术分享以下内容来自:MySQL Reference Manual — Online DDL Operations
在线 DDL 功能提供对原地表修改和并发 DML 的支持。此功能的优势包括:
- 在繁忙的生产环境中提高响应能力和可用性,因为使表不可用几分钟或几小时是不切实际的。
- 能够在 DDL 操作期间使用 LOCK 子句调整性能和并发之间的平衡。参见 LOCK 子句 。
- 比表复制方法使用的磁盘空间更少,I/O 开销也更小。
通常,您无需执行任何特殊操作即可启用在线 DDL。默认情况下,MySQL 在允许的情况下就地执行操作,并尽可能减少锁定。
您可以使用 ALGORITHM 和 LOCK 语句的子句来控制 DDL 操作的各种方面。这些子句位于语句的末尾,通过逗号与表和列规范分开。例如:
ALTER TABLE tbl_name ADD PRIMARY KEY (column), ALGORITHM=INPLACE, LOCK=NONE;
版本演进
MySQL Online DDL 功能自 5.6 版本正式引入,并在后续版本不断完善:
- MySQL 5.5 :MySQL 5.5 及之前,所有的 DDL 操作都是全程锁表(LOCK = EXCLUSIVE),仅支持 Fast Index Create(快速索引创建)。此时对 二级索引的增删 操作可以使用 Inplace 算法,从而避免重建整个表,但仍需对表加锁,阻塞写操作。其他变更仍只能采用复制表的方式。但是因为实现的问题,依然会阻塞 INSERT、UPDATE、DELETE 操作,造成的问题是:如果是在业务高峰期执行一条 DDL 语句,往往有明显的业务中断,从而出现直接引发“雪崩报警”,这也是 MySQL 早期版本长期被吐槽的原因之一。
- MySQL 5.6 :正式引入 Online DDL 概念,官方显著增加了可在线的 ALTER TABLE 类型,并允许在 DDL 执行时并发 DML,支持在不阻塞并发 DML 的情况下添加索引、修改自增值等操作。旨在显著减少(或消除)更改数据库对象所需的应用程序停机时间(该特性以下统称 Online DDL),从而减少重建表的需要。不过,并非所有 DDL 都支持在线模式,具体支持可以参考 各版本支持的详细情况 章节。
- MySQL 5.7 :在 5.6 的基础上扩展了对更多 DDL 操作的在线支持,例如支持在线重命名索引、在线增减数值类型长度、在线扩展 VARCHAR 长度等操作。但整体实现逻辑与 5.6 相似,依旧采用 Copy 和 Inplace 两种方式。
- MySQL 8.0 :大幅重构了 DDL 执行引擎,支持原子性 DDL(失败可回滚),并新增 ALGORITHM=INSTANT 算法。在 8.0.12+ 中,支持将列“秒加”到表的末尾,无需重建表;8.0.29 起 Instant 算法成为默认,可在任意位置添加或删除列。同时,MySQL 8.0 对 ALTER TABLE操作进行了重构与优化,引入 LOCK=NONE|SHARED|EXCLUSIVE 参数来更灵活地控制锁粒度和并发行为。
MySQL Online DDL详解:从历史演进到原理及使用
MySQL 8.0 新特性之 DDL 即时加列
Online DDL 解决的问题
Online DDL 的核心在于让 DDL 操作与 DML(查询/增删改)并发执行,从而避免长时间锁表。
原理
MySQL Online DDL 的底层实现主要依赖三种算法:COPY 、INPLACE ,以及在 MySQL 8.0.12+ 中引入的 INSTANT 。
- 复制表法(Copy Table)
COPY 是 Online DDL 中最常见的一种实现方式,它在后台模拟了传统 DDL 的重建流程。但在后台进行,从而减少了对在线业务的影响。其核心步骤如下:
- **创建临时表:** MySQL会创建一个与原始表结构相同的新临时表。
- **复制数据:** 将原始表中的数据复制到临时表中。 在数据复制期间,所有对原始表的 DML(数据操作语言)操作(INSERT、UPDATE、DELETE) 都会被捕获并记录为增量变更。
- **应用增量变更:** 当数据复制完成后,MySQL会暂停对原始表的DML操作一小段时间,然后将复制期间记录的所有增量DML操作应用到临时表上。
- **原子性替换:** 最后,MySQL会通过原子性的操作将原始表重命名,并将临时表重命名为原始表的名称。这个替换操作通常非常快,对业务的影响极小。
这种方式的优点是实现简单,兼容性好,但缺点是需要额外的磁盘空间(至少是原始表大小的一倍),并且在数据复制期间会消耗 CPU 和 I/O 资源。
- 原地变更法(In-Place)
对于某些特定的 DDL 操作(如添加、删除或重命名列,添加或删除索引等),MySQL 可以采用更高效的“原地变更”方式,即直接在原表上进行修改,而不需要创建临时表和复制数据。这种方式的效率更高,对系统资源的消耗更小,因为它避免了大量的数据复制。
原地变更的实现机制通常涉及对表的数据文件和索引文件进行直接修改。例如,添加新列可能只需要修改表的元数据信息,而不需要重写所有行数据。然而,并不是所有的 DDL 操作都能使用原地变更。
| 1 | 创建 frm(表结构定义文件)临时文件 | | ---
| 2 | 锁原表,不允许 DML(数据操作语言),允许查询 | | 3 | 根据聚集索引顺序构建新的索引项,按照顺序插入新的索引页 | | 4 | 原表升级锁,禁止读写,即原表暂停服务 | | 5 | rename 操作,替换原表的 frm 文件 |
根据是否需要重建表结构,又分为两种情况:
- 需要重建(Rebuild) :如添加索引、添加/删除列、修改列的 NULL 属性等操作需要重新组织聚簇索引。在此过程中,InnoDB 会后台构建新的表数据,同时缓存并发执行的 DML 操作。DDL 完成后再将缓存的 DML 增量应用到表上,实现变更和业务并行。
- 无需重建(No-Rebuild) :如删除索引、修改列名或默认值、修改自增值等操作只需更新表元数据即可,不改动行数据。
在 INPLACE 算法下,InnoDB 仍会对原表加元数据锁(MDL)以保证一致性:在数据转换阶段通常加 MDL 读锁(允许 DML,但不允许其他 DDL),在最后合并增量时加 MDL 写锁(阻止并发 DDL/DML)。由于数据并未真正移动到外部临时表,该过程对服务器来说是“原地”操作,减少了 IO 和空间开销。
- INSTANT 算法
只支持极少数简单操作(如修改字符集或在表末尾添加列)。此时 MySQL 仅修改数据字典中的元数据条目,不对表数据作任何变动,也无需表锁。由于仅更新元信息,所以 DDL 几乎瞬间完成,对业务没有任何阻塞。例如,MySQL 8.0.12 引入了 Instant 算法用于快速加列(仅限末尾列),8.0.29 起将其作为默认算法并支持任意位置添加和快速删除列。
说明: 在 Online DDL 过程中,为了保证数据一致性,MySQL 会对原表加上短暂的元数据锁。如在 COPY 或 INPLACE 的复制阶段对原表加 MDL 读锁,在应用增量阶段加 MDL 写锁;在最终替换表结构时,会再短暂地加独占锁重命名表。通过这种方式,Online DDL 保证了在大部分时间内业务可并发访问,只有在关键切换点才加锁。
关键参数: ALGORITHM 和 LOCK
在 ALTER TABLE 语句中,我们可以通过 ALGORITHM 和 LOCK 子句来控制 DDL 操作的行为:
- ALGORITHM : 指定DDL操作的算法,可选值有:
- INPLACE : 尝试原地变更,如果不支持则报错。
- COPY : 强制使用复制表法。
- INSTANT : (MySQL 8.0引入)某些操作可以在瞬间完成,无需重建表。
- DEFAULT : MySQL会自动选择最佳的算法,优先使用 INPLACE 的方式。
- LOCK : 指定DDL操作的锁定级别,可选值有:
- NONE : 允许并发读写。
- SHARED : 共享锁,允许并发读,但禁止并发写。
- EXCLUSIVE : 独占锁,禁止并发读写,指定 DDL 的表将被完全锁定,无法执行任何读写操作。
- DEFAULT : MySQL会自动选择最佳的锁定级别。
通常情况下,我们应该尽量选择 ALGORITHM=INPLACE 和 LOCK=NONE ,以实现最少的锁定和最高的可用性。
使用示例
在 ALTER TABLE 语句中,可以通过 ALGORITHM 和 LOCK 子句来启用和控制在线 DDL。例如,官方文档示例中提到使用原地算法:
ALTER TABLE tbl_name ADD PRIMARY KEY (col), ALGORITHM = INPLACE;
用户可以按需设置:如以下命令示例在添加列时尽量使用原地算法并允许并发读写:
ALTER TABLE mytable ADD COLUMN new_col INT DEFAULT 0 ALGORITHM = INPLACE, LOCK = NONE;
上述命令尝试在原表上增列并同时允许并发读写 developer.aliyun.com 。对于 MySQL 8.0.12 及以上版本,也可指定 ALGORITHM=INSTANT (仅限支持 Instant 的操作)来实现几乎即时的变更:
ALTER TABLE mytable ADD COLUMN new_col2 INT DEFAULT 1 ALGORITHM = INSTANT;
需要注意,Instant 算法仅支持在允许的位置(例如末尾)添加或删除列 MySQL 8.0 新特性之 DDL 即时加列 ;如果不指定算法(或指定 ALGORITHM=DEFAULT ),MySQL 会优先尝试 INPLACE,不行时回退到 COPY 模式
注意事项
集群模式下存在问题
在 Master-Slave 架构下,官方的 Online DDL 存在致命的缺陷,所以我们只能转向第三方工具。这里有 Percona 的公司的 pt-osc,是基于触发器的 Online DDL 的代表。以及比较新的,Github 的 gh-ost,是基于 Binlog 的。
gh-ost(Binlog 增量同步,无触发器)
pt-online-schema-change(触发器方式)
MySQL Online DDL 探究
针对生产环境,对于需要频繁读写的”大表“,执行 DDL 操作时,不推荐使用 MySQL 的在线模式 ,推荐使用第三方工具:
github.com/github/gh-o…
github.com/percona/per…
docs.percona.com/percona-too…
C Reference
MySQL Online DDL 详解:从历史演进到原理及使用
mysql 大表如何 ddl
dev.mysql.com/doc/refman/…
各版本支持的详细情况
doc.yonyoucloud.com/doc/mysql-5…
dev.mysql.com/doc/refman/…
dev.mysql.com/doc/refman/…
相关推荐
- oracle数据导入导出_oracle数据导入导出工具
-
关于oracle的数据导入导出,这个功能的使用场景,一般是换服务环境,把原先的oracle数据导入到另外一台oracle数据库,或者导出备份使用。只不过oracle的导入导出命令不好记忆,稍稍有点复杂...
- 继续学习Python中的while true/break语句
-
上次讲到if语句的用法,大家在微信公众号问了小编很多问题,那么小编在这几种解决一下,1.else和elif是子模块,不能单独使用2.一个if语句中可以包括很多个elif语句,但结尾只能有一个...
- python continue和break的区别_python中break语句和continue语句的区别
-
python中循环语句经常会使用continue和break,那么这2者的区别是?continue是跳出本次循环,进行下一次循环;break是跳出整个循环;例如:...
- 简单学Python——关键字6——break和continue
-
Python退出循环,有break语句和continue语句两种实现方式。break语句和continue语句的区别:break语句作用是终止循环。continue语句作用是跳出本轮循环,继续下一次循...
- 2-1,0基础学Python之 break退出循环、 continue继续循环 多重循
-
用for循环或者while循环时,如果要在循环体内直接退出循环,可以使用break语句。比如计算1至100的整数和,我们用while来实现:sum=0x=1whileTrue...
- Python 中 break 和 continue 傻傻分不清
-
大家好啊,我是大田。...
- python中的流程控制语句:continue、break 和 return使用方法
-
Python中,continue、break和return是控制流程的关键语句,用于在循环或函数中提前退出或跳过某些操作。它们的用途和区别如下:1.continue(跳过当前循环的剩余部分,进...
- L017:continue和break - 教程文案
-
continue和break在Python中,continue和break是用于控制循环(如for和while)执行流程的关键字,它们的作用如下:1.continue:跳过当前迭代,...
- 作为前端开发者,你都经历过怎样的面试?
-
已经裸辞1个月了,最近开始投简历找工作,遇到各种各样的面试,今天分享一下。其实在职的时候也做过面试官,面试官时,感觉自己问的问题很难区分候选人的能力,最好的办法就是看看候选人的github上的代码仓库...
- 面试被问 const 是否不可变?这样回答才显功底
-
作为前端开发者,我在学习ES6特性时,总被const的"善变"搞得一头雾水——为什么用const声明的数组还能push元素?为什么基本类型赋值就会报错?直到翻遍MDN文档、对着内存图反...
- 2023金九银十必看前端面试题!2w字精品!
-
导文2023金九银十必看前端面试题!金九银十黄金期来了想要跳槽的小伙伴快来看啊CSS1.请解释CSS的盒模型是什么,并描述其组成部分。...
- 前端面试总结_前端面试题整理
-
记得当时大二的时候,看到实验室的学长学姐忙于各种春招,有些收获了大厂offer,有些还在苦苦面试,其实那时候的心里还蛮忐忑的,不知道自己大三的时候会是什么样的一个水平,所以从19年的寒假放完,大二下学...
- 由浅入深,66条JavaScript面试知识点(七)
-
作者:JakeZhang转发链接:https://juejin.im/post/5ef8377f6fb9a07e693a6061目录...
- 2024前端面试真题之—VUE篇_前端面试题vue2020及答案
-
添加图片注释,不超过140字(可选)...
- 今年最常见的前端面试题,你会做几道?
-
在面试或招聘前端开发人员时,期望、现实和需求之间总是存在着巨大差距。面试其实是一个交流想法的地方,挑战人们的思考方式,并客观地分析给定的问题。可以通过面试了解人们如何做出决策,了解一个人对技术和解决问...
- 一周热门
- 最近发表
-
- oracle数据导入导出_oracle数据导入导出工具
- 继续学习Python中的while true/break语句
- python continue和break的区别_python中break语句和continue语句的区别
- 简单学Python——关键字6——break和continue
- 2-1,0基础学Python之 break退出循环、 continue继续循环 多重循
- Python 中 break 和 continue 傻傻分不清
- python中的流程控制语句:continue、break 和 return使用方法
- L017:continue和break - 教程文案
- 作为前端开发者,你都经历过怎样的面试?
- 面试被问 const 是否不可变?这样回答才显功底
- 标签列表
-
- git pull (33)
- git fetch (35)
- mysql insert (35)
- mysql distinct (37)
- concat_ws (36)
- java continue (36)
- jenkins官网 (37)
- mysql 子查询 (37)
- python元组 (33)
- mybatis 分页 (35)
- vba split (37)
- redis watch (34)
- python list sort (37)
- nvarchar2 (34)
- mysql not null (36)
- hmset (35)
- python telnet (35)
- python readlines() 方法 (36)
- munmap (35)
- docker network create (35)
- redis 集合 (37)
- python sftp (37)
- setpriority (34)
- c语言 switch (34)
- git commit (34)
