记一次线上数据库删除百万级数据

1|0背景


不知道有没有读者经历过删除线上数据库记录,反正这事对我来说是挺有压力的。激动的心,颤抖的手,万一删错了数据就麻烦了,影响数量大,领导会批评,还有复盘自己批评,想想就头大。那么就要在删除数据之前做好计划,避免删数据时发生意料之外的事情。记录一次删除线上数据。

业务以半年为一个周期,每一个周期体验参与用户在40w左右。新一期开始后过期体验用户的数据较大,会让数据库增删改查速度变慢,但这一部分数据对业务已经没有帮助了,所以要清理过期体验用户的数据。

一共要清理5张表:
A:数量 36w
B:数量 36w
C:数量 140w
D:数量 36w
E:数量 72w

2|0要求


对于大量数据的查询和删除不能使用一条语句完成,会造成数据库阻塞,特别是删除数据时会锁表或锁行。要减少对线上正常业务的影响,在删除数据的同时不能影响数据库正常增删改查,而且不能让数据库查询等待过长而导致API返回超时。所以查询和删除都需要分批完成。

3|0删除数据底层流程


简单的说明一下在删除数据时MySQL数据底层流程。
MySQL数据库分为两个部分:server层和存储引擎,如下图:

在删除一条记录时,流程分别是:

  1. 客户端连接到server层
  2. 分析器对sql语句进行词法分析和语法分析,知道是一条删除语句
  3. 优化器选择合适的索引去查找待删除的记录
  4. 执行器调用存储引擎删除所有记录
  5. 存储引擎将维护的数据内存里的记录标记为已删除
  6. 存储引擎根据刷盘规则将内存的记录写到磁盘中

以上就是删除一条语句的过程,因为每一个sql语句是一个事务,每一个事务都涉及到加锁,所以在以上的删除流程中,锁的使用是这样的:

  1. 如果查询待删除记录走的是索引,那么会将所有删除记录行加锁
  2. 如果查询待删除记录没有走索引,那么将会将整张表都锁起来,直到删除完成

4|0删除实施


针对最多140w的数据,肯定不能一次性删除,否则锁表的时间会让其他业务无法进行,同时要在删除时使用行锁而不是表锁。所以删除分为两步走:

  1. 使用分块查询,将所有记录的主键查询出来
  2. 根据主键分批删除,同时每一次删除间隔一定时间,异常捕获不影响删除流程

经过5张表的删除,得出以下脚本删除时对数据库影响较小

# 分批查询,只查询id def chunk_model(model, conditions, start_id=0, chunk_size=500): while True: models = list( model.select(model.id) .where(model.id > start_id, *conditions) .order_by(model.id.asc()) .limit(chunk_size) ) if not models: break yield models start_id = models[-1].id import time from app.camp.models import UserPlan plan_id_list = [33,34] delete_id_list = [] for chunk_data in chunk_model(UserPlan, [UserPlan.plan_id.in_(plan_id_list)]): print(chunk_data[0].id) for data in chunk_data: delete_id_list.append(data.id) # 分批删除 for id_index in range(0, len(delete_id_list), 1000): print(id_index) try: delete_ids = delete_id_list[id_index:id_index+1000] UserPlan.delete().where(UserPlan.id.in_(delete_ids)).execute() time.sleep(0.5) except Exception as e: print(id_index, e)

最多的140w数据耗时在10分钟左右,全程数据库无波动,业务没有影响。


__EOF__

本文作者goldsunshine
本文链接https://www.cnblogs.com/goldsunshine/p/16484247.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   金色旭光  阅读(1476)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示