Mysql-大表在线更新字段

612 阅读4分钟

背景

某一日

大厂面试官:线上有一张数据量级为几千万的表,需要新增一个字段,该如何处理呢

葫芦:目前还没有接触过类似的场景,大概的想法是建一张新表,双写的形式...

大厂面试官: 回去等通知

稀碎....

ps: 以下内容为参考网上大佬们的实现方案总结而来

实现

MySQL 在执行 ALTER TABLE 增加字段操作时,会对表进行短时间的写锁定以避免数据的修改冲突,但是锁定时间将取决于要添加的列的数量,列的大小以及表的大小。

在大表场景下,特别是千万级、亿级的大表,如果处理不当。这些操作往往会引发锁表的巨大隐患,特别是在生产环境中,一旦在变更表结构过程中,出现了长时间锁表,会导致用户产生的数据长时间无法正常变更到表中,进而导致服务功能异常,结果将是灾难性的

一般可能有以下想法

  • 停服, 在停服期间做表结构的变更,自然就可以防止对用户产生影响

  • 凌晨执行, 在用户较少的时间段内,做变更,尽量减少对用户产生影响

  • 使用换表, 但是缺点是复制数据到新表期间,如果用户在这期间做了update或delete操作,且数据发生在已经复制完成的部分,那么将无法感知到这部分数据,导致丢失掉用户的操作数据,风险太大

  • 使用存储过程, 缺点是执行时间会很久,且有可能影响到用户的DDL操作。因为为了防止每次循环修改时,锁住太多数据行,我们需要控制每次更新数据的行数,粒度不能太大,否则很有可能会锁住用户正在操作的数据行

以上的方案都有一定的缺陷,不够丝滑,会对线上业务造成一定的影响

pt-osc

pt-osc (在线模式更改表) 是一个来自 Percona Toolkit 工具包的命令行工具,用于在 MySQL 中进行在线模式更改表结构的操作。相比于传统的 ALTER TABLE 命令,pt-osc 有以下优势:

  • pt-osc 可以避免在执行修改表操作时对表的锁定,从而减小对服务器性能的影响。
  • pt-osc 可以同时进行多个表更改操作,从而避免了多次单独执行 ALTER TABLE 命令的繁琐工作。
  • pt-osc 可以监控表的修改操作,以便及时发现并修复可能出现的错误。

下面是使用 pt-osc 进行表更改的基本步骤

使用 pt-osc 工具修改表结构的主要步骤如下:

1、创建一个跟原表一模一样的新表,命名方式为'_正式表名_new';

2、使用alter语句将要变更的内容在新创建的新表上做变更,避免了对原表的alter操作;

3、在原表中创建3个触发器,分别是insert、update和delete,主要是用于原表在往新表复制数据时,如果用户有DDL操作,触发器能够将在这期间出现的DDL操作数据也写入到新表中,确保新表的数据是最新的,不会丢失掉用户的新操作数据;

4、按块拷贝数据到新表,拷贝过程对数据行持有S锁;

5、重命名,将原表重命名为老表,命名为“_正式表名_old”,将新表重命名为正式表,可通过配置决定执行完成后是否删除掉老表;

6、删除3个触发器;

pt-osc的使用

例如,如果要在名为 testdb 的数据库中的表 testtable 中添加一个名为 new_column 的字段,可以执行以下命令:

pt-online-schema-change --execute --alter "ADD COLUMN new_column INT" D=testdb,t=testtable  

该命令会在数据库 testdb 中对表 testtable 执行添加字段操作,并监控操作的细节。如果发现出现了错误,pt-osc 可以快速回滚修改操作,恢复原来的表结构

大体性能: 1600w的数据量级增加新字段,约7分钟

总结

  • pt-osc 可以帮助我们更好的对表字段进行变更

  • MySQL 5.6 以上版本支持并行索引创建,在执行新增索引操作时,在 ALTER TABLE 语句中添加 ALGORITHM=INPLACE, LOCK=NONE, ONLINE=ON 选项,指定使用 INPLACE 算法、禁用锁定、使用在线模式等选项,让 MySQL 引擎使用并行操作方式来创建索引,从而减少锁定表的时间

  • Mysql 8.0 的ALGORITHM=INSTANT 性能更好,可以达到秒级