在MySQL中实际删除3亿条记录的故事

介绍



嘿。我是ningenMe,网络开发人员。



如标题所示,我的故事是关于在MySQL中实际删除3亿条记录。



我对此很感兴趣,因此决定写一份备忘录(说明)。



开始-警报



我使用和维护的批处理服务器有一个常规过程,每天一次从MySQL收集上个月的数据。



通常,此过程大约需要1个小时才能完成,但是这次没有完成7到8个小时,并且警报并没有停止爬出...



寻找原因



我试图重新启动该过程,查看日志,但没有发现任何可怕的情况。

该请求已正确索引。但是,当我想知道出了什么问题时,我意识到数据库的大小很大。



hoge_table | 350'000'000 |


3.5亿条记录。索引似乎工作正常,只是速度很慢。



每月所需的数据收集量约为1200万条记录。看起来select命令花费了很长时间,并且事务很长时间没有执行。



D B



基本上,它是一个每天增加约40万条记录的表。该数据库本应仅收集最后一个月的数据,因此,计算是基于这样的事实,即它可以完全承受此数量的数据,但是不幸的是,不包括轮换操作。



这个数据库不是我开发的。我从另一位开发人员手中接手了,所以感觉就像是技术债务。



每天插入的数据量变大并最终达到极限的时刻到了。假设要处理如此大量的数据,则有必要将它们分开,但是不幸的是,这并未完成。



然后我介入。



更正



减少数据库本身并减少处理时间比更改逻辑本身更为合理。



如果擦除了3亿条记录,情况应该会发生很大的变化,所以我决定这样做……嗯,我认为肯定可以。



第1步



准备了可靠的备份后,我终于开始提交请求。



「提交要求」



DELETE FROM hoge_table WHERE create_time <= 'YYYY-MM-DD HH:MM:SS';


“ ...”



“ ...”



“嗯……没有答案。也许过程需要很长时间?” -我以为是,但以防万一我查看grafana并发现磁盘负载增长非常快。

“危险”-我再三考虑,立即停止了该请求。



第2步



分析完所有内容后,我意识到数据量太大,无法一口气删除所有内容。



我决定编写一个脚本,该脚本可以删除大约1,000,000条记录并运行它。



“我实现了脚本”



“现在肯定可以了,”我想



第三步



第二种方法可行,但事实证明非常耗时。

整洁地做所有事情,无需额外的精力,大约需要两个星期。但是,这种情况仍然无法满足服务要求,因此我不得不放弃它。



因此,这是我决定要做的事情:



复制表并重命名



从上一步开始,我意识到删除如此大量的数据会产生同样大的负载。因此,我决定使用insert从头开始创建一个新表,并将要删除的数据移动到该表中。



| hoge_table     | 350'000'000|
| tmp_hoge_table |  50'000'000|


如果使新表的大小与上述相同,则处理速度也应提高1/7。



创建表并重命名后,我开始将其用作主表。现在,如果我放下一个拥有3亿条记录的表,一切都会很好。

我发现截断或删除的开销要小于删除的开销,因此决定使用该方法。



性能



「提交要求」



INSERT INTO tmp_hoge_table SELECT FROM hoge_table create_time > 'YYYY-MM-DD HH:MM:SS';


「...」

「...」

「呃...?」



第4步



以为以前的想法会起作用,但是在提交插入请求后,出现了多个错误。MySQL不保留。



我已经非常疲倦,以至于我开始认为自己不再想要这样做了。



我坐下来思考着,意识到也许一次有太多插入请求……

我试图发送一个插入请求,要求数据库在1天之内处理大量数据。发生了!



好吧,此后,我们继续发送对相同数量数据的请求。由于我们需要删除每月的数据量,因此我们重复此操作约35次。



重命名表格



在这里,运气就在我这一边:一切顺利。



警报不见了



批处理速度提高了。



以前,此过程大约需要一个小时,而现在大约需要2分钟。



当我确信所有问题都解决了之后,我放弃了3亿条记录。我删除了电子表格并感到重生。



总结



我意识到旋转处理在批处理中被忽略了,这是主要问题。这种架构错误是浪费时间。



您是否认为通过从数据库中删除记录来增加数据复制负载?让我们不要重载MySQL。



那些精通数据库的人绝对不会遇到这样的问题。对于其他情况,希望本文对您有所帮助。



谢谢阅读!



如果您告诉我们您是否喜欢本文,我们将非常高兴,翻译是否清晰,对您有用吗?



All Articles