介绍
嘿。我是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。
那些精通数据库的人绝对不会遇到这样的问题。对于其他情况,希望本文对您有所帮助。
谢谢阅读!
如果您告诉我们您是否喜欢本文,我们将非常高兴,翻译是否清晰,对您有用吗?