摘要:在业界中有一个比较成熟的工具,针对大表的场景,可以在线进行Alter变更,且不会出现锁表的风险。除此之外,它还有其他的一些优点,让我们开始探索吧。

背景

大家在日常工作中,往往需要对数据库的表结构做变更,一般涉及到增删字段,修改字段属性等ALTER的操作。然而,在大表场景下,特别是千万级、亿级的大表,如果处理不当。这些操作往往会引发锁表的巨大隐患,特别是在生产环境中,一旦在变更表结构过程中,出现了长时间锁表,会导致用户产生的数据长时间无法正常变更到表中,进而导致服务功能异常,结果将是灾难性的。

一般执行这种Alter类型的变更,我们可能有以下的想法:

1、停服,在停服期间做表结构的变更,自然就可以防止对用户产生影响。但是,很多场景是不允许停服的。并且如果表的数据量达到上亿,那么需要停服时间可能需要十几个小时,甚至更长,这是极不现实的;

2、凌晨执行,在用户较少的时间段内,做变更,尽量减少对用户产生影响。但是如果出现锁表的话,万一有用户使用服务,服务将不可用;

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

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

那么针对以上实际的需求,就没有一个很好的工具,来解决我们的痛点吗?其实在业界中,就有一个比较成熟的工具,针对大表的场景,可以在线进行Alter变更,且不会出现锁表的风险。除此之外,它还有其他的一些优点,让我们开始探索吧。

一、pt-osc是什么

pt-online-schema-change是Percona-toolkit一员,通过改进原生ddl的方式,达到不锁表在线修改表结构的效果。在Percona的官网中,关于pt-osc工具,也特别提到了ALTER表不会出现锁表的特性。

针对上面谈到的避免锁表、感知用户更新删除动作等,ps-osc工具是怎么解决的呢?

pt-osc主要执行步骤如下:

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

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

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

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

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

6、删除3个触发器;

二、pt-osc的安装

在linux系统中安装步骤:

--下载安装包
wget  http://szxge1-sw.artifactory.cd-cloud-artifact.tools.huawei.com/artifactory/CommonComponent/common/tool/percona-toolkit-3.1.0.tar.gz--解压安装包
tar -zxvf percona-toolkit-3.1.0.tar.gz--安装依赖环境
yum install perl-ExtUtils-CBuilder perl-ExtUtils-MakeMaker
yum -y install perl-Digest-MD5
cd percona-toolkit-3.1.0
perl Makefile.PL--编译
make
make install
yum install mariadb--安装Mysql
yum install perl-DBD-MySQL

三、pt-osc的使用

pt-osc工具使用起来很简单,直接在linux命令行输入pt-osc格式的命令,即可直接执行。

以Mysql数据库增加一个名字是MARK的字段为例:

pt-online-schema-change --user="root" --password="*****" --host="数据库IP" --port=3306 --alter "ADD COLUMN MARK TINYINT NULL DEFAULT 1 COMMENT 'mark source region is 1';" D=my_test,t=t_test --no-drop-old-table --execute --print --no-check-replication-filters --charset=utf8 --no-check-unique-key-change --max-load="Threads_running=100" --critical-load="Threads_running=300" --recursion-method=none;

在上面的语句中:

1、user和password分别为数据库执行变更操作的用户名、密码,需要高权限;

2、host为数据库的IP地址;

3、port为数据库的端口号;

4、alter后面跟上具体的alter语句;

5、D为database名字;

6、t为要执行变更的表名;

7、no-drop-old-table就是不要删除

8、charset,字符集,使用utf8;

9、max-load,在复制数据时,工具会监控数据库中正在运行的线程数,如果大于配置的Threads_running值,那么会暂停复制,直到小于该值。以此防止对数据库造成较大压力,影响现网业务正常使用;

10、critical-load,默认为50,在每个块之后检查SHOW GLOBAL STATUS,与max-load不同的是,如果负载太高,,直接中止,而不是暂停。可根据自己数据库情况斟酌配置阈值;

注意:在--alter后面跟着的变更语句中,列名不可以加`符号,否则会出现报错。如--alter "ADD COLUMN MARK TINYINT NULL DEFAULT 1 COMMENT 'mark source region is 1';",MARK字段加了`符号,就会出现错误,COMMENT后面有`符号无影响。

下面是使用pt-osc工具,实际执行一个作业时,打印出来的信息。为了安全起见,部分日志信息做了隐藏忽略。

[root@ttt ~]#  `pt-online-schema-change --user="root" --password="*****" --host="数据库IP" --port=3306 --alter "ADD COLUMN MARK TINYINT NULL DEFAULT 1 COMMENT 'mark source region is 1';" D=my_test,t=t_test --no-drop-old-table --execute --print --no-check-replication-filters --charset=utf8 --no-check-unique-key-change --max-load="Threads_running=100" --critical-load="Threads_running=300" --recursion-method=none;`No slaves found.  See --recursion-method if host EulerOS-BaseTemplate has slaves.Not checking slave lag because no slaves were found and --check-slave-lag was not specified.Operation, tries, wait:analyze_table, 10, 1copy_rows, 10, 0.25create_triggers, 10, 1drop_triggers, 10, 1swap_tables, 10, 1update_foreign_keys, 10, 1Altering `my_test`.`t_test`...Creating new table...CREATE TABLE `my_test`.`_t_test_new` (`ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '递增ID',.............建表语句数据................Created new table my_test._t_test_new OK.Altering new table...ALTER TABLE `my_test`.`_t_test_new` ADD COLUMN MARK TINYINT NULL DEFAULT 1 COMMENT 'mark source region is 1';Altered `my_test`.`_t_test_new` OK.2020-10-14T11:14:48 Creating triggers...2020-10-14T11:14:48 Created triggers OK.2020-10-14T11:14:48 Copying approximately 346697 rows...INSERT LOW_PRIORITY IGNORE INTO `my_test`.`_t_test_new` (`id`, ..建表语句信息.... FROM `my_test`.`_t_test_new` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= ?)) AND ((`id` <= ?)) LOCK IN SHARE MODE /*pt-online-schema-change 31340 copy nibble*/SELECT /*!40001 SQL_NO_CACHE */ `id` FROM `my_test`.`t_test` FORCE INDEX(`PRIMARY`) WHERE ((`id` >= ?)) ORDER BY `id` LIMIT ?, 2 /*next chunk boundary*/2020-10-14T11:14:53 Copied rows OK.2020-10-14T11:14:53 Analyzing new table...2020-10-14T11:14:53 Swapping tables...RENAME TABLE `my_test`.`t_test` TO `my_test`.`_t_test_old`, `my_test`.`_t_test_new` TO `my_test`.`t_test`2020-10-14T11:14:53 Swapped original and new tables OK.Not dropping old table because --no-drop-old-table was specified.2020-10-14T11:14:53 Dropping triggers...DROP TRIGGER IF EXISTS `my_test`.`pt_osc_my_test_t_test_del`DROP TRIGGER IF EXISTS `my_test`.`pt_osc_my_test_t_test_upd`DROP TRIGGER IF EXISTS `my_test`.`pt_osc_my_test_t_test_ins`2020-10-14T11:14:54 Dropped triggers OK.Successfully altered `my_test`.`t_test`.

四、性能对比

前面介绍了很多pt-osc的优点,以及良好的特性。那么实际使用效果到底怎么样呢?在测试环境中,专门做了一个测试,让大家有更加直观的感受。

在测试库中,准备了一张1600万数据的大表,目标为对大表添加一个字段,分别使用存储过程和pt-osc工具,进行测试。

4.1 使用存储过程

首先使用存储过程做测试,为防止锁表,每次只更新200行。整个变更从开始到完成,需要耗费90分钟。其实,存储过程在执行过程中,如果恰好用户也在DDL操作存储过程正在变更的数据行,还有可能会锁住用户的数据,导致用户不能变更成功。

4.2 使用pt-osc工具

pt-osc从开始执行到变更完成,耗时7分钟左右,速度非常快。在执行的过程中,测试环境的服务连接到该数据库,并执行多个会操作该表的任务,整个过程中,任务能够正常执行,未出现异常情况。

5、结语

ps-osc的上述优点,在现网环境的不停服等要求下,能够优雅地帮助我们实施变更,且保证在变更期间,数据库不会受到锁表、过载等的影响,进而保证了业务能够正常运转。

本文分享自华为云社区《千万级、亿级大表在线不锁表变更字段与索引》,原文作者:active_zhao 。

点击关注,第一时间了解华为云新鲜技术~

亿级大表在线不锁表变更字段与索引相关推荐

  1. 亿级大表分库分表实战总结(万字干货,实战复盘)

    亿级大表分库分表实战总结(万字干货,实战复盘) 以下文章来源于阿丸笔记 ,作者阿丸笔记 阿丸笔记 分库分表的文章网上非常多,但是大多内容比较零散,以讲解知识点为主,没有完整地说明一个大表的切分.新架构 ...

  2. 一入职!就遇到MySQL亿级大表优化....

    作者丨jia-xin 出处: https://www.cnblogs.com/YangJiaXin/p/10828244.html "前段时间刚入职一家公司,就遇到了 MySQL 亿级大表优 ...

  3. [NewLife.XCode]分表分库(百亿级大数据存储)

    NewLife.XCode是一个有15年历史的开源数据中间件,支持netcore/net45/net40,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode. 整个系列教程会大量 ...

  4. 千亿级大数据如何存储的?

    在社区,有用户提到了一个这样的问题,千亿级大数据如何存储.这位同学给出了以下的使用背景. 我们关注到他的问题描述,虽然整体数据量并不是很大,但从应用场景上来看,非常符合时序数据库(Time-Serie ...

  5. mysql联表查询count错误_关于count(*)和联表查询和锁表的问题

    刚开始学MySQL,在描述时候假如有不对的地方,希望各位大大指出. 本人在看书的时候看到了这么一句,在生产环境中请不要随意使用count(*),原因是它将会进行表级锁定(inno DB下). 原因是最 ...

  6. [生产库实战] 如何使用触发器对生产库上亿级大表进行实时同步

    触发器迁移数据和Oracle 物化视图(MV)的原理相同,通过在源表创建Trigger,记录源表的DML操作日志,然后通过存储过程同步DML受影响的记录,达到目标表和源表数据一致的效果.此方法只是对P ...

  7. MariaDB 10.3 instant ADD COLUMN亿级大表毫秒级加字段

    加字段是痛苦的,需要对表进行重建,尤其是对亿级别的大表,虽然Online DDL可以避免锁表,但如果在主库上执行耗时30分钟,那么再复制到从库上执行,主从复制就出现延迟.使用instant ADD C ...

  8. 数据库改造:怎样用MySQL对10亿级订单量进行分库分表?

    一.背景 随着公司业务增长,如果每天1000多万笔订单的话,3个月将有约10亿的订单量,之前数据库采用单库单表的形式已经不满足于业务需求,数据库改造迫在眉睫. 二.订单数据如何划分 我们可以将订单数据 ...

  9. 基于Ganos百行代码实现亿级矢量空间数据在线可视化

    简介: 本文介绍如何使用RDS PG或PolarDB(兼容PG版或Oracle版)的Ganos时空引擎提供的数据库快显技术,仅用百行代码实现亿级海量几何空间数据的在线快速显示和流畅地图交互,且无需关注 ...

最新文章

  1. 如何检查linux系统的负载高低
  2. crypto——明文攻击
  3. 买房子,就该用线性回归
  4. Consumer group理解深入
  5. Socket之TCP服务器【Python】
  6. 2019蓝桥杯国赛B组第九题
  7. .net core 2.0学习笔记(二):Hello World amp;amp; 进阶
  8. el table 固定表头和首行_表头太太太复杂了,如何批量打印?简单!
  9. 洛谷 CSP2019-J2 自测 P5661 公交换乘
  10. 数据结构与算法 3:二叉树,遍历,创建,释放,拷贝,求高度,面试,线索树
  11. 【aRsenal-1】用R创建Word和PowerPoint文档
  12. EOS 钱包开发(JAVA)
  13. python实现电脑自动开机_python自动循环定时开关机(非重启)测试
  14. 如何对自动驾驶技术进行全面检验?
  15. 华为机试6-质因数分解
  16. element-ui下载文件功能
  17. 计算机中求声音传输时间公式,计算机常用计算公式汇总
  18. Latex-加通讯作者的小信封标记
  19. BP神经网络做分类+隐含层节点确定+红酒数据为例
  20. strftime( ) 函数说明

热门文章

  1. 在Vrep中如何创建基于QT的GUI
  2. ROS笔记(2) Kinetic 的安装和配置
  3. 简书java前端_Java前端知识之JSP
  4. 计算机开机自启文件夹,电脑开机自动打开文件夹解决方法
  5. conda如何升级pytorch_第一节 PyTorch简介及环境配置
  6. java oxm_spring使用OXM进行对象XML映射解析
  7. Oracle DBA 经典面试题
  8. echo图片延迟加载js
  9. ubuntu14.04 remmina远程连接rdp服务器失败解决办法
  10. Asp.net MVC4 与 Web Form 并存