mysql MDL读写锁阻塞,以及online ddl造成的“插队”现象

本文深入探讨MySQL中MDL(元数据锁)的工作原理及其对DML与DDL操作的影响,解析在线DDL如何通过MDL锁实现高效并发控制。

看mysql45讲遇到一个问题

 

为什么C等待拿锁之后,D也会阻塞?其实这里并没有解释清楚。因为如果按并发理解的话,C,D应当是同等级,都有可能拿到锁的。但C读写锁互斥,D读读不互斥,这样的话就跟上图所述相悖了。就,查了一下。

(鸣谢 一梦如是YFL提供的文章

首先是MDL(metaData Lock)的概念。元数据锁是server层的锁,表级锁,主要用于隔离DML(Data Manipulation Language数据操纵语言如select)和DDL(Data Definition Language,数据定义语言,如改表头新增一列)操作之间的干扰。每执行一条DML、DDL语句时都会申请MDL锁,DML操作需要MDL读锁,DDL操作需要MDL写锁(MDL加锁过程是系统自动控制,无法直接干预,读读共享,读写互斥,写写互斥)

申请MDL锁的操作会形成一个队列,队列中写锁获取优先级高于读锁。一旦出现写锁等待,不但当前操作会被阻塞,同时还会阻塞后续该表的所有操作。事务一旦申请到MDL锁后,直到事务执行完才会将锁释放。(这里有种特殊情况如果事务中包含DDL操作,mysql会在DDL操作语句执行前,隐式提交commit,以保证该DDL语句操作作为一个单独的事务存在,同时也保证元数据排他锁的释放,例如id 44的语句改为<begin;alter table testok add z varchar(10) not Null;select * from testok;>,此时一旦alter语句执行完成会马上提交事务(autocommit=1),后面的select就在本次事务之外,其执行完成后不会持有读锁)

这样就能解释通为什么session C被阻塞后,session D也运行不了的原因了。

 

然后进入下一个问题:

 

我也试了一下,确实如此,加上begin之后,session D会“插队”到session C前面,也就是原本的队列结构竟然出现了 “插队”现象,???

这个问题就要涉及到online ddl了。

由于ddl执行时如果锁表的话会严重影响性能,不锁表又难搞定操作期间dml语句的影响,于是mysql推出了全新的online ddl概念,即通过:

1. 拿MDL写锁
2. 降级成MDL读锁
3. 真正做DDL
4. 升级成MDL写锁
5. 释放MDL锁

5个步骤,第一步拿读锁是为确保没有其他ddl语句在执行;第三步是自己申请一块空间开始改表结构、填数据;等填好了之后,执行第四步,这期间由于持有读锁,可以确保不会有其他ddl语句造成不一致性;最后等拿到写锁,把表一替代就搞定了。

这样就看出来端倪了。上图中session A,Bcommit后,sessionC确实拿到了写锁,只不过由于锁降级,令sessionD拿到了读锁。但session D没有commit,因此session C在执行online commit到第三步后,又给阻塞了。所以就出现了类似于“插队”的现象。

如果想验证的话,可以再开一个begin;select...的session,就叫sessionE吧。然后让刚刚没commit的session D commit一下,会发现这次session C并没有阻塞

mdl各个session流程实例

<think>我们正在讨论MySQL的在线DDL功能。根据引用内容,MySQL Online DDL允许在修改表结构的同时保持数据库的可用性,这对于生产环境非常重要。让我们逐步解析其原理和使用方法。 ### 一、MySQL Online DDL原理 引用[1]提到MySQL Online DDL的工作机制包括准备阶段和执行阶段: 1. **准备阶段**: - 检查与评估:验证DDL语法、用户权限以及资源需求。 - 选择执行策略:根据操作类型和表结构,决定使用COPY、INPLACE或INSTANT算法。 2. **执行DDL操作**: - **COPY算法**(传统方式): 创建临时表,复制原表数据并应用修改,期间阻塞写操作(早期DDL方式)。 - **INPLACE算法**(原地重建): 避免复制整个表,而是在原表上重建。多数情况下允许并发DML操作(需重建表)。 - **INSTANT算法**(MySQL 8.0+): 仅修改元数据,不涉及数据复制或重建,适用于添加列等操作(秒级完成)。 引用[3][4]补充: - Online DDL在5.6版本引入,通过行日志(row log)记录DDL期间的DML操作,并在最后应用这些变更,确保数据一致性。 - 不同DDL操作的支持情况(算法、是否锁表)取决于MySQL版本和操作类型。例如: - 添加索引:通常支持INPLACE(并发DML) - 删除列:可能重建表(INPLACE但耗时较长) ### 二、使用方法与注意事项 1. **语法示例**: ```sql -- 添加索引(INPLACE算法) ALTER TABLE tbl_name ADD INDEX idx_name (col), ALGORITHM=INPLACE, LOCK=NONE; -- 添加列(INSTANT算法,8.0+) ALTER TABLE tbl_name ADD COLUMN col INT, ALGORITHM=INSTANT; ``` 2. **关键参数**: - `ALGORITHM`:指定算法(`COPY`/`INPLACE`/`INSTANT`),建议由MySQL自动选择。 - `LOCK`:控制并发级别(`NONE`/`SHARED`/`EXCLUSIVE`),推荐`LOCK=NONE`允许并发DML。 3. **注意事项**: - **版本兼容性**:INSTANT算法仅限MySQL 8.0以上版本。 - **空间要求**:INPLACE算法需要额外磁盘空间(约为原表大小)。 - **长事务风险**:DDL执行期间若有未提交的长事务,可能导致元数据锁(MDL)等待。 - **监控进度**:MySQL 8.0+可通过`performance_schema`监控DDL进度。 ### 三、替代方案(引用[4]) 当原生Online DDL无法满足需求时,可使用第三方工具: - **pt-online-schema-change**(Percona): 通过触发器同步增量数据,需创建临时表。 - **gh-ost**(GitHub): 模拟从库读取binlog同步数据,无需触发器,降低主库负载。 > **总结**:MySQL Online DDL是数据库结构变更的核心技术,合理选择算法和参数可最大限度减少业务中断。对于关键操作,建议先在测试环境验证。 §§相关问题§§ 1. MySQL Online DDL中COPY、INPLACE、INSTANT三种算法的具体适用场景是什么? 2. 如何监控MySQL Online DDL的执行进度和影响? 3. 在MySQL 5.7版本中,哪些常见的DDL操作支持`LOCK=NONE`(允许并发DML)? 4. 使用pt-online-schema-change或gh-ost工具时,如何避免对主库性能造成影响?</think>### MySQL Online DDL 原理与使用详解 #### **一、核心原理** 1. **工作流程** - **准备阶段** MySQL 检查语法、权限、资源,并基于操作类型(如加索引/改字段)自动选择算法:`COPY`、`INPLACE` 或 `INSTANT`[^1]。 - **执行阶段** - **COPY 算法**(传统):创建临时表复制数据,全程锁表(阻塞读写)[^3]。 - **INPLACE 算法**:原地修改数据文件,**允许并发 DML 操作**(需重建表时短暂阻塞写)[^1][^3]。 - **INSTANT 算法**(MySQL 8.0+):仅修改元数据(如加列),秒级完成且**不阻塞读写**[^1]。 2. **数据一致性保障** - 通过 **行日志 (row log)** 记录 DDL 期间的 DML 操作,最后应用增量变更[^3][^4]。 - 元数据锁(MDL)确保 DDL 开始时无活跃事务[^4]。 #### **二、使用方法** 1. **语法示例** ```sql -- 显式指定算法(推荐) ALTER TABLE users ADD COLUMN age INT, ALGORITHM=INPLACE, -- 可选值:INPLACE/COPY/INSTANT LOCK=NONE; -- 并发控制:NONE/SHARED/EXCLUSIVE ``` 2. **关键操作支持** | 操作类型 | 支持算法 | 是否锁表 | |----------------------|-------------------|------------------| | 加索引 | INPLACE (Online) | LOCK=NONE 时无锁 | | 删列/改列类型 | INPLACE (Rebuild) | 短暂写阻塞 | | 加列(MySQL 8.0+) | INSTANT | 全程无锁 | | 改表注释 | INSTANT | 全程无锁 | 3. **注意事项** - **版本依赖**:`INSTANT` 仅限 MySQL 8.0+;`INPLACE` 需 5.6+。 - **空间要求**:`INPLACE` 需要额外磁盘空间(约 1.2 倍原表大小)。 - **风险操作**:主键修改、数据类型转换可能强制使用 `COPY` 算法[^3]。 #### **三、替代方案(原生 DDL 不适用时)** 1. **第三方工具** - **pt-online-schema-change**(Percona): 通过触发器同步增量数据,需创建临时表[^4]。 - **gh-ost**(GitHub): 模拟从库读取 binlog 同步数据,无需触发器,对主库压力更小[^4]。 > **总结建议**:优先使用原生 Online DDL(指定 `ALGORITHM=INPLACE, LOCK=NONE`),大表操作或低版本 MySQL 可选用 gh-ost 工具。
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值