我发现自己想要在很多应用程序中滚动删除早于(x)-days的行。在高流量桌上最有效地做到这一点的最佳方法是什么?
例如,如果我有一个存储通知的表,我只想保留7天。或高分我只想保持31天。
现在我保留一行存储发布的纪元时间,然后运行一个每小时运行一次的cron作业,并以这样的增量删除它们:
DELETE FROM my_table WHERE time_stored < 1234567890 LIMIT 100
我这样做直到mysql_affected_rows返回0。
我曾经一次完成所有操作,但是当INSERTS堆积起来时,应用程序中的所有内容都会挂起30秒左右。添加LIMIT可以缓解这种情况,但我想知道是否有更好的方法可以做到这一点。
答案 0 :(得分:57)
尝试创建将在您想要的时间间隔后自动在数据库上运行的事件。
这是一个例子: 如果要从某个表'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
以在每次运行后保留事件。您可以在此处找到更多信息:http://www.mysqltutorial.org/mysql-triggers/working-mysql-scheduled-event/
答案 1 :(得分:28)
通过删除仅包含该数据的分区(或多个分区),通常可以轻松地从分区表中删除失去其实用性的数据。相反,在某些情况下,通过添加一个或多个新分区来特别存储该数据,可以极大地促进添加新数据的过程。
参见例如本节将介绍如何应用它:
这一个:
答案 2 :(得分:2)
不是单独对表执行删除,而是先尝试收集匹配的键,然后再执行DELETE JOIN
鉴于上面的示例查询
DELETE FROM my_table WHERE time_stored < 1234567890 LIMIT 100 ;
您可以将LIMIT排除在外。
假设您要删除超过31天的数据。
让我们以秒计算31天(86400 X 31 = 2678400)
这是算法
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;
如果密钥收集时间少于5分钟,则每隔5分钟运行一次此查询。
试一试!!!
这是应该加快关键收集的一些事情。添加以下索引:
ALTER TABLE my_table ADD INDEX time_stored_id_ndx (time_stored,id);
这将更好地支持填充delete_keys表的子查询,因为这提供了覆盖索引,以便仅从索引中检索字段。
由于您必须经常删除,您可能希望每两个月尝试一次
OPTIMIZE TABLE my_table;
这会在所有那些令人讨厌的小删除每5分钟两个月后对表进行碎片整理
答案 3 :(得分:1)
在我的公司,我们也有类似的情况。我们有一个包含过期密钥的表。我们有一个cron来清理它:
DELETE FROM t1 WHERE expiration < UNIXTIME(NOW());
每小时运行一次,但我们遇到的问题与您遇到的问题类似。我们将它增加到每分钟一次。然后每分钟6次。使用基本上执行查询的bash脚本设置cron,然后休眠几秒钟并重复直到分钟结束。
增加的频率显着减少了我们删除的行数。这缓解了争论。这是我要去的路线。
但是,如果您发现仍有太多行要删除,请使用限制并在它们之间进行休眠。例如,如果要删除50k行,请在它们之间进行2秒睡眠的10k块。这将有助于查询堆叠,并允许服务器在这些批量删除之间执行一些正常操作。
答案 4 :(得分:1)
您可能需要考虑在设计中引入master/slave (replication)解决方案。如果将所有读取流量转移到从站,则打开主站以处理“即时”CRUD活动,然后将其复制到从站(您的读取服务器)。
由于您要删除这么多记录,因此您可能需要考虑在删除行的表上运行optimize。
答案 5 :(得分:0)
最终使用它仅保留最后100行,因此在频繁执行(每分钟)时会有很大的滞后时间
delete a from tbl a left join (
select ID
from tbl
order by id desc limit 100
) b on a.ID = b.ID
where b.ID is null;