MySQL线上大表DDL避免锁表的解决方案

 更新时间:2025年04月23日 09:56:08   作者:i人事_徐志斌  
在系统研发过程中,随着业务需求千变万化,避免不了调整线上MySQL DDL数据表的操作,也就是ALTER TABLE操作,但是如果这张线上表是个大表,这时候DDL操作这个过程耗时非常久,会出现锁表现象,所以本文介绍了避免线上锁表的方案,需要的朋友可以参考下

1、锁表问题

在系统研发过程中,随着业务需求千变万化,避免不了调整线上MySQL DDL数据表的操作,也就是ALTER TABLE操作,例如:加个索引、加个字段等…

但是如果这张线上表是个大表,也就是说该表可能存在百万、千万、甚至上亿条数据,这时候DDL操作这个过程耗时非常久,并且这个执行阶段存在一个极端现象:锁表,锁表会带来很大的问题,那就是直接导致线上大表读写阻塞。这对大部分系统来说,是无法接受的。

现在有很多避免线上锁表的方案,例如:

  • 停机执行(直接系统停机维护…不推荐 )
  • Online DDL(MySQL 5.6版本以上支持,不推荐 )
  • pt-online-schema-change(推荐 )

本次主要介绍pt-online-schema-change,因为Online DDL这个方案争议还是比较多的,并不建议使用,具体原因参考其他文章,本文重点不在这里。

2、pt-online-schema-change 原理

参考文档:pt-online-schema-change — Percona Toolkit Documentation

  1. 首先,根据原表创建新表,但是并不会拷贝原表中的数据,_new结尾
  2. 新表执行 DDL 语句,因为是空表,执行速度很快
  3. 原表加3个触发器,捕获变更(insert/update/delete),避免迁移过程中,新表数据不实时同步原表
  4. 批量拷贝原表数据到新表
  5. 数据一致后,会删除原表,留下新表作为生产表。这个过程通常是瞬时的,新表此时已经包含了所有的最新数据

3、pt-online-schema-change 实战

3.1、准备数据

本次我使用阿里云的 Ubuntu 22.04 服务器,上面安装了一台MySQL数据库,MySQL最好设置为innodb_autoinc_lock_mode=2,否则在高并发的写入情况下,很容易产生锁等待以及死锁,我先通过下述 SQL 脚本新增 700w 测试数据:

DELIMITER $$

CREATE PROCEDURE generate_data()
BEGIN
    DECLARE i INT DEFAULT 0;
    WHILE i < 7000000 DO
        INSERT INTO user (user_name, pass_word, create_time)
        VALUES 
        (CONCAT('user_', UUID()), 
         CONCAT('password_', FLOOR(RAND() * 10000)), 
         CURDATE());
        SET i = i + 1;
    END WHILE;
END $$

DELIMITER ;

CALL generate_data();

3.2、安装工具

Percona Toolkit 是一个集合了多个实用工具的工具包,专门用于 MySQL 数据库的管理和优化,而 pt-online-schema-change 是其中一个非常有用的工具,所以这里安装 Percona Toolkit

apt install percona-toolkit

3.3、模拟锁表

先通过 Navicat 依次执行下述几个命令,模拟锁表现象发生,DDL操作前的事务没有提交,就会一直锁住:

# 1.耗时查询SQL(耗时几分钟)
select * from user

# 2.给大表加字段
ALTER TABLE user ADD COLUMN email30 VARCHAR (255) COMMENT '用户邮箱'

# 3.分页查询
select * from user limit 1,10

接着就通过命令查看,出现锁表现象:

SHOW FULL PROCESSLIST

DDL后续所有操作,都会被阻塞,没办法正常执行,会导致生产环境SQL直接卡死。

3.4、解决锁表

使用 pt-online-schema-change 进行 DDL 模版大概如下:

pt-online-schema-change --host=主机ip --user=MySQL账号 --password=MySQL密码 --alter "DDL语句" D=数据库名,t=表名 --print --execute

重新模拟锁表现象:

# 1.耗时查询SQL(耗时几分钟)
select * from user

# 2.给大表加字段(注意⚠️:这个在服务器上执行,不要在Navicat上)
pt-online-schema-change --host=172.16.0.217 --user=root --password=root --alter "ADD COLUMN address VARCHAR(255) COMMENT '家庭住址'" D=pt-online-test,t=user --print --execute

# 3.分页查询
select * from user limit 1,10

最后会发现,select * from user limit 1,10查询操作不会被阻塞(但是执行会变慢一些),当然pt-online-schema-change官方提供了许多参数细节,有兴趣可以访问官网自行查看。

以上就是MySQL线上大表DDL避免锁表的解决方案的详细内容,更多关于MySQL大表DDL锁表的资料请关注脚本之家其它相关文章!

相关文章

  • MYSQL分页limit速度太慢的优化方法

    MYSQL分页limit速度太慢的优化方法

    这篇文章主要介绍了MYSQL分页limit速度太慢的优化方法,需要的朋友可以参考下
    2016-05-05
  • mysql 8.0.18 mgr 搭建及其切换功能

    mysql 8.0.18 mgr 搭建及其切换功能

    这篇文章主要介绍了mysql 8.0.18 mysql搭建及其切换功能,本文通过实例代码给大家讲解的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-12-12
  • MySQL的commit是如何commit源码解析

    MySQL的commit是如何commit源码解析

    这篇文章主要为大家介绍了MySQL的commit是如何commit源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-06-06
  • MySQL之视图、储储过程、触发器使用及说明

    MySQL之视图、储储过程、触发器使用及说明

    文章介绍了MySQL中的视图、存储过程与触发器:视图是动态生成的虚拟表,用于简化查询和数据访问控制;存储过程是预编译的SQL集合,提升数据处理效率;触发器在表操作前后自动执行,保障数据完整性与操作日志记录
    2025-09-09
  • 一步步教你在Navicat上如何停止正在运行的MYSQL语句

    一步步教你在Navicat上如何停止正在运行的MYSQL语句

    很多时候我们会提交一些耗时比较长的sql,可能出现mysql服务器内存或者CPU暴增,引起报警,甚至影响其他业务,下面这篇文章主要给大家介绍了关于在Navicat上如何停止正在运行的MYSQL语句的相关资料,需要的朋友可以参考下
    2023-03-03
  • 在MySQL现有表中添加自增ID的方法步骤

    在MySQL现有表中添加自增ID的方法步骤

    当在MySQL数据库中,自增ID是一种常见的主键类型,它为表中的每一行分配唯一的标识符,在某些情况下,我们可能需要在现有的MySQL表中添加自增ID,以便更好地管理和索引数据,在本文中,我们将讨论如何在MySQL现有表中添加自增ID,并介绍相关的步骤和案例
    2023-09-09
  • MySQL查看操作记录几种常用的方法

    MySQL查看操作记录几种常用的方法

    在数据库的日常管理中,了解表的操作历史是非常重要的,MySQL提供了多种方式来查看表的操作日志,包括查询日志、慢查询日志以及二进制日志等,这篇文章主要介绍了MySQL查看操作记录几种常用的方法,需要的朋友可以参考下
    2025-09-09
  • 安装使用Percona XtraBackup来备份恢复MySQL的教程

    安装使用Percona XtraBackup来备份恢复MySQL的教程

    这篇文章主要介绍了安装使用Percona XtraBackup来备份恢复MySQL的教程,文中的示例环境基于CentOS系统,需要的朋友可以参考下
    2015-12-12
  • mysql之连接超时wait_timeout问题及解决方案

    mysql之连接超时wait_timeout问题及解决方案

    这篇文章主要介绍了mysql之连接超时wait_timeout问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • CentOS下彻底卸载mysql的方法

    CentOS下彻底卸载mysql的方法

    这篇文章主要为大家详细介绍了CentOS下彻底卸载mysql的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-09-09

最新评论