深入分析mysql给表加字段涉及到的锁

知其然要知其所以然,探索每一个知识点背后的意义,你知道的越多,你不知道的越多,一起学习,一起进步,如果文章感觉对您有用的话,关注、收藏、点赞,有困惑的地方请评论,我们一起交流!


一、元数据锁(Metadata Lock, MDL)

1. MDL的作用

  • 保护表结构一致性:防止在表结构变更过程中,其他会话修改表定义或执行可能导致元数据冲突的操作(如DROP TABLE、ALTER TABLE等)。
  • 控制并发:确保在DDL操作期间,DML操作(SELECT/INSERT/UPDATE/DELETE)与DDL操作之间的隔离性。

2. MDL的锁类型与冲突

  • 共享锁(SHARED_READ/SHARED_WRITE)
    DML操作(SELECT/INSERT等)会隐式获取共享MDL锁,允许多个会话并发执行。
  • 排他锁(EXCLUSIVE)
    DDL操作(ALTER TABLE等)需获取排他MDL锁,阻塞其他所有MDL请求,直到DDL完成。

3. 加字段过程中的MDL行为

  • MySQL 5.5及之前
    • 整个ALTER TABLE过程持有排他MDL锁,阻塞所有DML操作
    • 导致业务完全不可写/读,直到DDL完成。
  • MySQL 5.6+(Online DDL)
    • 阶段1(准备阶段):短暂获取排他MDL锁,检查表结构并初始化操作。
    • 阶段2(执行阶段):降级为共享MDL锁,允许并发DML操作。
    • 阶段3(提交阶段):再次短暂获取排他MDL锁,替换表文件并提交变更。
    • 总阻塞时间:主要集中在准备和提交阶段,通常为毫秒级。

二、表级锁(LOCK)

1. 表级锁的类型

  • READ锁:允许其他会话读,阻塞写。
  • WRITE锁:阻塞其他会话的所有读写操作。

2. 加字段时的表级锁行为

  • 传统COPY算法 (非Online DDL):
    • 创建临时表并复制数据时,需持有WRITE锁,阻塞所有DML
    • 示例:未指定ALGORITHM=INPLACE时,MyISAM表的ALTER操作。
  • Online DDL(INPLACE算法)
    • 仅在准备和提交阶段短暂获取WRITE锁,执行阶段允许并发DML。
    • 示例:InnoDB表添加字段(非全文索引、非空间索引等场景)。

三、不同场景下的锁行为

1. 支持Online DDL的ADD COLUMN

  • 场景 :InnoDB表添加普通字段(如VARCHARINT),且不涉及索引重建。

  • 锁行为

    • 准备阶段:短暂排他MDL锁 + WRITE锁(创建临时表)。
    • 执行阶段:共享MDL锁,允许并发DML。
    • 提交阶段:短暂排他MDL锁 + WRITE锁(表替换)。
  • 示例

    sql 复制代码
    ALTER TABLE users 
    ADD COLUMN phone VARCHAR(20) DEFAULT NULL,
    ALGORITHM=INPLACE, 
    LOCK=NONE;

2. 不支持Online DDL的ADD COLUMN

  • 场景:添加字段涉及存储格式变更(如修改列顺序)、添加全文索引、空间索引。
  • 锁行为
    • 全程排他MDL锁 + WRITE锁,阻塞所有DML。
    • 示例:MyISAM表添加字段,或InnoDB表添加FULLTEXT索引。

3. 长事务阻塞MDL

  • 场景:存在未提交的长事务(如未提交的SELECT或事务型DML)。
  • 问题:DDL操作在准备阶段需等待长事务释放共享MDL锁,导致后续所有MDL请求排队。
  • 现象SHOW PROCESSLIST显示Waiting for table metadata lock
  • 解决:终止长事务或调整DDL执行窗口。

四、锁冲突的监控与诊断

1. 监控MDL锁

sql 复制代码
-- 查看当前MDL锁等待
SELECT * FROM performance_schema.metadata_locks 
WHERE OWNER_THREAD_ID != sys.ps_thread_id(0);

2. 查看阻塞会话

sql 复制代码
-- 显示等待MDL锁的会话
SELECT 
  p.id AS blocked_pid,
  p.user AS blocked_user,
  p.host AS blocked_host,
  b.id AS blocking_pid,
  b.user AS blocking_user,
  b.host AS blocking_host
FROM information_schema.innodb_lock_waits w
JOIN information_schema.processlist p ON w.requesting_pid = p.id
JOIN information_schema.processlist b ON w.blocking_pid = b.id;

五、优化建议

1. 优先使用Online DDL

  • 指定ALGORITHM=INPLACELOCK=NONE

    sql 复制代码
    ALTER TABLE users 
    ADD COLUMN phone VARCHAR(20), 
    ALGORITHM=INPLACE, 
    LOCK=NONE;

2. 避免高并发时执行DDL

  • 选择业务低峰期操作,减少锁冲突概率。

3. 监控并清理长事务

sql 复制代码
-- 查找运行时间超过60秒的事务
SELECT * FROM information_schema.innodb_trx 
WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60;

4. 使用第三方工具

  • gh-ost:无触发器、基于binlog的在线表结构变更工具,完全避免锁表。
  • pt-online-schema-change:通过创建影子表同步数据,仅在切换时短暂锁表。

六、总结

场景 锁类型 阻塞范围 优化方案
Online DDL(INPLACE) 短暂排他MDL + WRITE锁 仅准备和提交阶段 指定ALGORITHM=INPLACE
COPY算法(非Online) 全程排他MDL + WRITE锁 所有DML操作 使用第三方工具(如gh-ost)
长事务阻塞 MDL共享锁未释放 DDL及后续查询排队 监控并终止长事务

通过合理选择Online DDL、避免长事务干扰,并借助工具降低锁冲突,可显著减少加字段操作对业务的影响。

相关推荐
熊大如如3 小时前
Java 反射
java·开发语言
猿来入此小猿3 小时前
基于SSM实现的健身房系统功能实现十六
java·毕业设计·ssm·毕业源码·免费学习·猿来入此·健身平台
goTsHgo4 小时前
Spring Boot 自动装配原理详解
java·spring boot
卑微的Coder4 小时前
JMeter同步定时器 模拟多用户并发访问场景
java·jmeter·压力测试
pjx9874 小时前
微服务的“导航系统”:使用Spring Cloud Eureka实现服务注册与发现
java·spring cloud·微服务·eureka
炒空心菜菜4 小时前
SparkSQL 连接 MySQL 并添加新数据:实战指南
大数据·开发语言·数据库·后端·mysql·spark
多多*5 小时前
算法竞赛相关 Java 二分模版
java·开发语言·数据结构·数据库·sql·算法·oracle
爱喝酸奶的桃酥5 小时前
MYSQL数据库集群高可用和数据监控平台
java·数据库·mysql
唐僧洗头爱飘柔95276 小时前
【SSM-SSM整合】将Spring、SpringMVC、Mybatis三者进行整合;本文阐述了几个核心原理知识点,附带对应的源码以及描述解析
java·spring·mybatis·springmvc·动态代理·ioc容器·视图控制器
骑牛小道士6 小时前
Java基础 集合框架 Collection接口和抽象类AbstractCollection
java