滚动式删除旧行的最佳方法是什么?
我发现自己希望在许多应用程序中滚动删除比(x)日更早的行。 在高stream量的桌子上最有效地做到这一点的最佳方法是什么?
例如,如果我有一个存储通知的表,我只想保留这些7天。 或者我只想保持31天的高分。
现在,我保持一个存储发布时间的行,并运行一个每小时运行一次的cron作业,并以这样的增量删除它们:
DELETE FROM my_table WHERE time_stored < 1234567890 LIMIT 100
我这样做,直到mysql_affected_rows返回0。
我曾经一次这样做,但是导致应用程序中的所有内容都挂起了30秒左右,而INSERTS堆积起来。 添加限制工作来缓解这一点,但我想知道是否有更好的方法来做到这一点。
检查MySQL分区 :
失去其有用性的数据通常可以通过删除仅包含该数据的分区(或分区)从分区表中轻松删除。 相反,添加新数据的过程在某些情况下可以通过添加一个或多个新的分区来专门存储该数据而大大方便。
请参阅这篇文章,以获得如何应用它的一些想法:
使用分区和事件计划程序修剪归档表
和这个:
按date分区:快速操作
尝试创build将在您想要的时间间隔后自动运行在数据库上的事件。
这里是一个例子:如果你想从某个表'tableName'中删除超过30天的条目,那么有列条目'datetime'。 然后下面的查询每天运行,这将需要清理行动。
CREATE EVENT AutoDeleteOldNotifications ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY ON COMPLETION PRESERVE DO DELETE LOW_PRIORITY FROM databaseName.tableName WHERE datetime < DATE_SUB(NOW(), INTERVAL 30 DAY)
我们需要添加ON COMPLETION PRESERVE
来保持每次运行后的事件。 你可以在这里find更多的信息: http : //www.mysqltutorial.org/mysql-triggers/working-mysql-scheduled-event/
不要单独对表执行删除操作,请尝试先收集匹配键,然后执行DELETE JOIN
给你上面的示例查询
DELETE FROM my_table WHERE time_stored < 1234567890 LIMIT 100 ;
你可以离开LIMIT。
假设你想删除超过31天的数据。
我们以秒计算31天(86400 X 31 = 2678400)
- 从关键聚会开始
- 接下来,索引键
- 然后,执行DELETE JOIN
- 最后,放下收集的密钥
这是algorithm
CREATE TABLE delete_keys SELECT id FROM my_table WHERE 1=2; INSERT INTO delete_keys SELECT id FROM ( SELECT id FROM my_table WHERE time_stored < (UNIX_TIMESTAMP() - 2678400) ORDER BY time_stored ) A LIMIT 100; ALTER TABLE delete_keys ADD PRIMARY KEY (id); DELETE B.* FROM delete_keys INNER JOIN my_table B USING (id); DROP TABLE delete_keys;
如果密钥收集less于5分钟,则每5分钟运行一次该查询。
试一试 !!!
更新2012-02-27 16:55 EDT
这是应该加快重点收集多一点。 添加以下索引:
ALTER TABLE my_table ADD INDEX time_stored_id_ndx (time_stored,id);
这将更好地支持填充delete_keys表的子查询,因为这提供了一个覆盖索引,以便只从索引中检索这些字段。
更新2012-02-27 16:59 EDT
既然你必须经常删除,你可能想每两个月尝试一次
OPTIMIZE TABLE my_table;
在所有那些令人讨厌的小删除每隔5分钟两个月之后,这将整理表格
您可能要考虑在您的devise中引入主/从(复制)解决scheme。 如果您将所有读取的stream量转移到从属设备上,您可以打开主设备来处理“即时”CRUD活动,然后将其复制到从属设备(您的读取服务器)。
而且,由于您正在删除如此多的logging,因此您可能需要考虑在要删除的行的表上对其进行优化 。
在我的公司,我们也有类似的情况。 我们有一个包含有到期的密钥的表。 我们有一个cron来运行清理:
DELETE FROM t1 WHERE expiration < UNIXTIME(NOW());
每小时运行一次,但是我们遇到了类似的问题。 我们增加到每分钟一次。 然后每分钟6次。 用一个基本上是查询的bash脚本安装一个cron,然后睡几秒钟,并重复,直到分钟到了。
增加的频率显着减less了我们删除的行数。 这减轻了争议。 这是我会走的路线。
但是,如果您发现仍有太多要删除的行,请使用该限制,然后在它们之间进行睡眠。 例如,如果你有50k行要删除,做一个10k的块与他们之间2秒的睡眠。 这将帮助查询堆积起来,并且允许服务器在这些批量删除之间执行一些正常的操作。