在MySQL中删除数百万行

我最近发现并修复了一个我正在处理的网站中的一个错误,这个错误导致了表中数百万重复的数据行,即使没有它们(仍然是数百万),这些数据行也相当大。 我可以很容易地find这些重复的行,并可以运行一个删除查询来杀死他们。 问题是试图一次性删除这么多行就locking了很长一段时间,如果可能,我想尽量避免。 我可以看到摆脱这些行的唯一途径,而不是取消网站(通过locking表):

  1. 编写一个脚本,在一个循环中执行数千个较小的删除查询。 这将理论上解决locking表问题,因为其他查询将能够进入队列并在删除之间运行。 但是它仍然会对数据库造成很大的负担,并且需要很长时间才能运行。
  2. 重命名表并重新创build现有的表(它现在将是空的)。 然后在重命名的表上进行清理。 重新命名新表,将旧名重新命名并将新行合并到已重命名的表中。 这是需要相当多的步骤,但应该完成的工作与最小的中断。 这里唯一棘手的部分就是所讨论的表格是一个报表,所以一旦它被重新命名,而空的表格被放置到位,那么所有的历史报告都会消失,直到我把它放回原处。 另外,由于存储数据的types,合并过程可能会有点痛苦。 总的来说,这是我现在可能的select。

我只是想知道是否有其他人之前有过这个问题,如果是的话,你怎么处理它,而不会取消网站,并希望尽可能减less,如果有任何中断用户? 如果我采用2号或者其他类似的方法,我可以把这些东西安排在深夜运行,并在第二天早些时候进行合并,让用户提前知道,这不是什么大问题。 我只是想看看有没有人有更好或更简单的方法来做清理的想法。

DELETE FROM `table` WHERE (whatever criteria) ORDER BY `id` LIMIT 1000 

清洗,冲洗,重复,直到零行受到影响。 也许在一个脚本,重复之间睡一两秒钟。

我还build议在表中添加一些约束,以确保这不会再发生在你身上。 一百万行,每次1000次,将需要1000次重复的脚本才能完成。 如果脚本每3.6秒运行一次,您将在一个小时内完成。 别担心。 你的客户不太可能注意到。

以下删除1,000,000个logging,一次一个。

  for i in `seq 1 1000`; do mysql -e "select id from table_name where (condition) order by id desc limit 1000 " | sed 's;/|;;g' | awk '{if(NR>1)print "delete from table_name where id = ",$1,";" }' | mysql; done 

你可以将它们组合在一起,并删除table_name其中IN(id1,id2,.. idN)我肯定也没有太多的困难

我将使用优秀的Maatkit公用程序包(用于MySQLpipe理的一堆Perl脚本)中的mk-archiver。Maatkit来自O'Reilly“高性能MySQL”一书的作者Baron Schwartz。

我们的目标是低影响,前瞻性的工作,将旧数据从表格中删除,而不会影响OLTP查询。 您可以将数据插入到另一个表中,而不需要在同一台服务器上。 您也可以使用适合LOAD DATA INFILE的格式将其写入文件。 或者你也可以不做,在这种情况下,它只是一个增量DELETE。

它已经build立了用于小批量归档不需要的行,作为奖励,它可以将删除的行保存到文件中,以防止将查询选中要删除的行。

无需安装,只需抓住http://www.maatkit.org/get/mk-archiver并运行perldoc(或阅读网站)以获取文档。

一次批量做2000行。 中间承诺。 一百万行不是那么多,这将是快速的,除非你有很多索引在桌子上。

根据mysql文档 , TRUNCATE TABLEDELETE FROM的快速替代方法。 尝试这个:

  TRUNCATE TABLE table_name 

我试了五十万行,这是在两分钟内完成的。

注意:截断操作不是事务安全的; 在活动事务或活动表locking过程中尝试一个错误时发生错误

Interesting Posts