繁难形象下业务场景,有一张 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://clwxseo.com/wangluoyouhua/9449.html