作者:dbapower
链接:https://blog.51cto.com/suifu/2135599

背景

Part1:写在最前

当一张单表10亿数据量的表放在你面前,你将面临着什么?

Part2:背景介绍

为了提升数据库资源利用率,一个实例中,在不互相影响,保证业务高效的前提下,我们会将同一个大业务下的不同小业务放在一个实例中,我们的磁盘空间是2T,告警阈值为当磁盘剩余空间10%时发出短信告警。笔者接到某业务主库磁盘剩余空间告警的短信后,经过一番查探,发现从几天前开始,有一张表的数据量增长非常快,而在之前,磁盘空间下降率还是较为平缓的,该表存在大字段text,其大批量写入更新,导致磁盘消耗迅猛。

我们首先来看下该表的表结构:

mysql> CREATE TABLE `tablename_v2` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,`No` varchar(64) NOT NULL DEFAULT '',`Code` varchar(64) NOT NULL DEFAULT '' ,`log` varchar(64) DEFAULT '' ,`log1` varchar(64) DEFAULT '' ,.....`Phone` varchar(20) DEFAULT '',`createTime` bigint(20) unsigned NOT NULL DEFAULT '0',`updateTime` bigint(20) unsigned NOT NULL DEFAULT '0',PRIMARY KEY (`id`),UNIQUE KEY `uk_mailNo` (`No`,`Code`),KEY `idx_Phone` (`Phone`)
) ENGINE=InnoDB AUTO_INCREMENT=9794134664 DEFAULT CHARSET=utf8;

与业务了解得知,该表几乎没有删除操作,由于数据量过大,我们模糊使用auto_increment来作为表数量预估值,避免count()操作对线上造成的影响。

Part3:案例分析

与业务沟通了解后得知,该表可以清理4个月以前的老旧数据,因此可以使用delete的方式清除,而我们通过表结构可以看出,该表在设计之初,并没有对updateTime列创建索引,因此以时间为范围去进行delete操作,这显然是不合理的。

经过与业务协商,我们确定了可以将id作为删除条件,删除id<2577754125之前的数据

也就是说,此时的delete语句变为了:

mysql> delete from tablename_v2 where id <2577754125;

且不说delete操作有多慢,直接执行这样的SQL也会有诸如长事务告警,从库大量延迟等并发症产生,因此绝不能在生产库上进行这种大批量的危险操作。

实战

Part1:监控

从监控图我们能看出磁盘下降的趋势:

监控显示,从6月14日-6月18日期间,磁盘消耗最为严重,与业务沟通得知,618期间大促引发该表存储量激增导致。

Part2:实战操作

我们通过查看binlog发现,集群中binlog的刷新量虽不说像笔者上个案例那样多么迅猛,但也绝不是老实本分

我们可以看出,在高峰期间,binlog的刷新间隔最短达到了2分钟写满1.1GB的binlog。因此笔者与业务沟通后,首先清理binlog日志,将 expire_logs_days从7天调整至3天。

同时,清理一些能够清理的无用日志、废旧文件等等。

我们也能在上面的监控图看到在做完这些清理操作后,磁盘空间剩余从4%提升至12%,但随后依旧保持原有速率下降。

Part3:pt-archiver

真凶找到了,我们怎么办,别急,使用pt-archiver。pt-archiver工具是percona工具集的一员,是归档MySQL大表数据的最佳轻量级工具之一。他可以实现分chunk分批次归档和删除数据,能避免一次性操作大量数据带来的各种问题。

闲话不多说,一向本着实战的原则,我们直接上命令:

pt-archiver --source
h=c3-helei-db01.bj,D=helei,t=tablename_v2,u=sys_admin,p=MANAGER
--where 'id<2577754125' --purge --progress 10000 --limit=10000
--no-check-charset --txn-size=10000 --bulk-delete --statistics --max-lag=20
--check-slave-lag c3-helei-db02.bj

简单说下常用的参数:

Warning:警告这里就又有个小坑了,的确,我们使用bulk-delete参数能够增加删除速率,相比不使用bulk-delete速度能够提升10倍左右,但问题也就显现出来,在使用上述命令期间,发现binlog每秒写入量激增,这又回到了我们说的,哪些情况会导致binlog转为row格式。

首先我们需要了解到使用bulk-delete时,sql是如下执行的:

mysql> delete from tablename_v2 where id >xxx and id < xxx limit 10000.

如果您之前关注过笔者的文章,应该知道,当使用了delete from xxx where xxx limit 语法时,会将binlog_format从mixed转为row,这样的话,删除的同时,binlog由于转为了row格式也在激增,这与我们的预期是不符的。

因此最终的命令为:

pt-archiver --source
h=c3-helei-db01.bj,D=helei,t=tablename_v2,u=sys_admin,p=MANAGER
--where 'id<2577754125' --purge --progress 10000 --limit=10000
--no-check-charset --txn-size=10000  --statistics --max-lag=20
--check-slave-lag c3-helei-db02.bj

去掉了bulk-delete,这样的话就能够保证正常的delete,而不加limit,binlog不会转为row格式导致磁盘消耗继续激增。

对于Innodb引擎来说,delete操作并不会立即释放磁盘空间,新的数据会优先填满delete操作后的“空洞”,因此从监控来看就是磁盘不会进一步消耗了,说明我们的pt-archiver工具删除是有效的。

Part4:困惑

首先我们要知道,当你面对一张数据量庞大的表的时候,有些东西就会受限制,例如:

  1. 不能alter操作,因为这会阻塞dml操作。
  2. 对于本案例,空间本就不足,也不能使用pt-online工具来完成。

对于不能alter其实是比较要命的,比如开发要求在某个时间段尽快上线新业务,而新业务需要新增列,此时面对这么庞大的量级,alter操作会异常缓慢。

因此,笔者与研发沟通,尽快采用物理分表的方式解决这个问题,使用物理分表,清理表的操作就会很容易,无需delete,直接drop 老表就可以了。其次,物理分表让alter语句不会卡住太久,使用pt-online工具也不会一次性占据过多的磁盘空间诱发磁盘空间不足的告警。

再有就是迁移TiDB,TiDB相较MySQL更适合存储这类业务。

Part5:再谈binlog_format

我们选取其中高峰期的binlog发现其update操作转为了row格式,记录了所有列变更前后的所有信息,而binlog中并未出现update xxx limit这种操作,那又会是什么引发的row格式记录呢?

这里这篇文章又抛出一个新的案例,在官网那篇何时mixed转row格式中又一个没有记录的情况

官方文档:

When running in MIXED logging format, the server automatically switches from statement-based to row-based logging under the following conditions:
When a DML statement updates an NDBCLUSTER table.
When a function contains UUID().
When one or more tables with AUTO_INCREMENT columns are updated and a trigger or stored function is invoked. Like all other unsafe statements, this generates a warning if binlog_format = STATEMENT.
When any INSERT DELAYED is executed.
When a call to a UDF is involved.
If a statement is logged by row and the session that executed the statement has any temporary tables, logging by row is used for all subsequent statements (except for those accessing temporary tables) until all temporary tables in use by that session are dropped.
This is true whether or not any temporary tables are actually logged.
Temporary tables cannot be logged using row-based format; thus, once row-based logging is used, all subsequent statements using that table are unsafe. The server approximates this condition by treating all statements executed during the session as unsafe until the session no longer holds any temporary tables.
When FOUND_ROWS() or ROW_COUNT() is used. (Bug #12092, Bug #30244)
When USER(), CURRENT_USER(), or CURRENT_USER is used. (Bug #28086)
When a statement refers to one or more system variables. (Bug #31168)

我们这个案例中又出现了一个新的因素就是:

当表结构中存在多个唯一索引(包括主键id),本案例中存在主键和UNIQUE KEY `uk_mailNo`这个唯一索引,且使用了

INSERT ... ON DUPLICATE KEY UPDATE

这时,mysql binlog_format就会被转为row格式,这个内容也是记录在官网的其他章节:

https://dev.mysql.com/doc/refman/5.5/en/insert-on-duplicate.html

也就是说,只要业务解决了使用这种语法插入的话,磁盘空间下降迅猛的原因也能够缓解不少。我们统计发现,qps更高的其他业务中,binlog保留7天的磁盘消耗量在60GB

而该业务我们仅仅保留3天binlog,却依旧消耗了430GB的磁盘空间,这已经超过了我们整个2T磁盘空间的5分之一了。

总结

通过这个案例,我们能够了解到什么情况下binlog_format会由MIXED格式转为ROW格式,以及触发的一系列并发症和解决办法,还有pt工具pt-archiver的使用。由于笔者的水平有限,编写时间也很仓促,文中难免会出现一些错误或者不准确的地方,不妥之处恳请读者批评指正。喜欢笔者的文章,右上角点一波关注,谢谢!

delete mysql 大表_无语了,直到今天,我才揪出MySQL磁盘消耗迅猛的“真凶”!相关推荐

  1. mysql bigint转string_无语了,直到今天,我才揪出MySQL磁盘消耗迅猛的“真凶”!...

    作者:dbapower 链接:https://blog.51cto.com/suifu/2135599 背景 Part1:写在最前 当一张单表10亿数据量的表放在你面前,你将面临着什么? Part2: ...

  2. 揪出MySQL磁盘消耗迅猛的真凶

    当一张单表10亿数据量的表放在你面前,你将面临着什么? 为了提升数据库资源利用率,一个实例中,在不互相影响,保证业务高效的前提下,我们会将同一个大业务下的不同小业务放在一个实例中,我们的磁盘空间是2T ...

  3. c mysql win8.1,Win8/8.1/Win7小技巧:揪出C盘空间占用的真凶 - IT之家

    不少使用Win8.Win8.1的用户不难发现,原先只占用20G大小的系统盘,随着使用时间的增加,C盘的磁盘空间不断减少,那这部分减少的空间去哪里的? 由于Windows系统的特殊环境,一般减少的空间都 ...

  4. mysql 大表 备份_MySQL大表备份的简单方法

    MySQL大表备份是一个我们常见的问题,下面就为您介绍一个MySQL大表备份的简单方法,希望对您学习MySQL大表备份方面能有所帮助. 这里所说的大表是超过4G以上的表,我目前见到过最大为60多G的单 ...

  5. mysql大表数据抽取_从云数据迁移服务看MySQL大表抽取模式

    摘要:MySQL JDBC抽取到底应该采用什么样的方式,且听小编给你娓娓道来. 小编最近在云上的一个迁移项目中被MySQL抽取模式折磨的很惨.一开始爆内存被客户怼,再后来迁移效率低下再被怼.MySQL ...

  6. MySQL大表传输表空间的坑

    MySQL大表传输表空间的坑 最近刚帮业务线拆分完数据库, 源环境遗留了一张700G的大表, 虽说现在不用了, 但是业务方还是不希望删掉, 于是打算把这张表迁移到归档库, 这样有需要是还可以查询. 7 ...

  7. 解决MYSQL大表问题-实战篇(二)

    #首先上表结构 CREATE TABLE `sys_history` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`did` bigint(20) NOT NUL ...

  8. 史上最全MySQL 大表优化方案(长文)

    转载自  史上最全MySQL 大表优化方案(长文) 当MySQL单表记录数过大时,增删改查性能都会急剧下降,可以参考以下步骤来优化: 一.单表优化 除非单表数据未来会一直不断上涨,否则不要一开始就考虑 ...

  9. MySQL 大表优化方案(1)

    转载自  干货!!!MySQL 大表优化方案(1) 当MySQL单表记录数过大时,增删改查性能都会急剧下降,可以参考以下步骤来优化: 单表优化 除非单表数据未来会一直不断上涨,否则不要一开始就考虑拆分 ...

最新文章

  1. 一款NPN三极管测量: BC547C
  2. 招人信息,请斟酌后联系偶!
  3. iOS中都有什么设计模式?各个设计模式的作用 (转载)
  4. Windows Azure SDK 1.6让Visual Studio下的Azure开发更高效
  5. 分布式/微服务必配APM系统,SkyWalking让你不迷路
  6. MathType安装教程,以及部分功能变灰,重新点亮
  7. FlashFXP 自动上传备份到指定FTP服务器的方法
  8. 汇编 DOS系统功能调用
  9. Matlab 根据状态方程,绘制相轨迹
  10. 市场营销渠道四个步骤?
  11. ROOT工具为漏洞利用大开“方便之门”
  12. python给excel添加超链接_《python3教程》 python用xlwt,超链接到另一sheet,如何设置HYPERLINK...
  13. CodeWarrior for S12(X) V5.1 Special详细安装过程
  14. 沃邮箱 android,沃邮箱Android客户端产品体验报告
  15. 前度字符串转数组_leetcode每日一题
  16. 2022最新自动化测试面试题及答案
  17. 执行Transact-SQL语句或批处理时发生异常
  18. matlab9级标度法,satty 标度法
  19. 经典游戏的⑨⑨⑨个隐藏系统
  20. C#语言实例源码系列-虚拟键盘

热门文章

  1. centos安装java的jdk
  2. scrapy的post登录:renren
  3. SQL Server AlwaysOn中的几个误区
  4. 分布式集群的Session问题
  5. 如何让.net程序自动运行在管理员权限下
  6. Spring MVC的工作原理,我们来看看其源码实现
  7. ThinkPHP5显示数据库字段内容
  8. js数组对象的常用方法
  9. 宿舍助手app——个人工作第四天
  10. 创建一个catkin工作空间