1. 首页 > 百货 > 母婴用品

慢 SQL 打爆监控!亿级数据表的删除问题

慢 SQL 打爆监控!亿级数据表的删除问题

type 由于没有索引放在 SQL 中是巨大瓶颈,必须得去掉!datachange_lasttime 也可以从 SQL 中拿出来,查出来之后在内存中再做 type 和>

背景

简单抽象下业务场景,有一张 MySQL 表用来存储用户的操作日志,需要依赖这个日志来做一些业务逻辑的判断,并且每个用户可以存在多条日志,所以可想而知,随着时间的推移,这张表肯定是会越来越大的,必须要做治理。

秉持着最简原则,我们暂时不考虑分库分表,数据能删则删,因为表中数据其实并不是每一条都有用,梳理了下业务之后,我们最终的治理方向就是:

我们可以抽象出这样一张表就命名为 log 吧,它有如下字段:

type 没有索引并且也不适合做索引。

删除数据的条件:

以上就是背景,应该比较清楚了

早期方案

首先大表删除的基本方针一定是批量删除,即分批查,分批删。

最基本的方案就是把>

 id  logdatachange_lasttime      

查一次就根据 id 批量删除一次,每次查 limit 条,停止条件就是查不出来数据了

失败的优化方案

早期方案在数据量级几千万的时候还是没问题的,因为我们这个删除只需要离线运行,所以用定时 job 跑就可以,对业务基本没啥影响。

但随着表越来越大,上亿之后,这条 SQL 直接卡住,慢查询告警猛增,已经没有办法正常完成删除了。

type 由于没有索引放在 SQL 中是巨大瓶颈,必须得去掉!datachange_lasttime 也可以从 SQL 中拿出来,查出来之后在内存中再做 type 和>

 id  log t_user_pop_log  id 

分页查询图方便我直接用的 MyBatis PageHelper,但是很快我就为此付出代价,就是总是有脏数据没删干净,我们举个例子分析下:

但是很明显这个停止查询的条件存在问题,如果恰好这一页的所有数据全都是 “type=c”,也就是这一页的数据都是不能删的数据,那么循环就会卡在这一页,因为这一页的数据永远不会发生变化

成功的优化方案

我们看失败方案,其实可以发现失败的最根本原因是 MyBatis Pagehelper 的 offset 的计算不对,考虑我们自己做分页,不用 MyBatis Pagehelper,这样就改成如下方式来分批查询:

  t_user_pop_log id    id 

这条 SQL 中只涉及主键 id,速度是非常快的:

上述方案很容易想到一个点,那就是 startId 可以不需要每次都从 1 开始。

每个月删除一次,那其实除了第一次,后续的删除只需要删除一个月的数据,只有第一次删除是需要扫描三个月前的所有数据。举个例子:

那么 startId 的初始取值逻辑就是:

以上,在首次删除的时候,扫描的数据量非常大,可以考虑加一点 sleep,防止 DB 进程被打满。

本网站的文章部分内容可能来源于网络和网友发布,仅供大家学习与参考,如有侵权,请联系站长进行删除处理,不代表本网站立场,转载者并注明出处:https://jmbhsh.com/muyingyongpin/36357.html

联系我们

QQ号:***

微信号:***

工作日:9:30-18:30,节假日休息