删除旧记录 - MySQL

时间:2013-12-16 14:58:56

标签: mysql sql sql-delete

我目前正在寻找解决我遇到的基本问题的方法:删除旧记录。

为了解释这种情况,我有一个表,我将其称为table1,记录数量减少。通常它保持为空,因为它用于中继消息。这些消息在添加到数据库后的两秒钟内被读取,并被删除,以便不再读取它们。

但是,如果其中一个应该接收来自table1的消息的客户端脱机,则有几个消息可能会挂起。有时数百。有时甚至数千甚至数十万,甚至更多。

这不仅会损害客户端的性能,而且必须处理大量的消息,还会损坏保存在内存中的数据库,并且应该保留最少量的记录。

考虑到客户端每秒检查新邮件,删除旧记录的最佳方法是什么?我考虑过添加时间戳,但这不会影响性能:它必须在插入时计算时间戳吗?我已经尝试过了,所有这些查询都以慢查询日志结束。

最佳解决方案是什么?我已经考虑过检查表是否在过去5秒内被更改,如果没有,我们可以安全地确保所有应该中继的消息已经被中继,并且可以擦除它。但是怎么做呢?

我已经考虑过每隔几分钟运行一次的事件,但我不确定如何实现对select / insert / delete查询没有(或无意义)影响的事情。

PS:当我注意到有些客户端处于脱机状态时,就会出现这种情况,并且有800万条消息待处理。

编辑:

我忘了提到存储引擎是MEMORY,因此所有记录都保存在RAM中。这是我想摆脱这些记录的主要原因:因为数百万条甚至不存在的记录存放在RAM中,会对系统资源产生影响。

以下是错误日志的摘录:

# Query_time: 0.000283  Lock_time: 0.000070 Rows_sent: 0  Rows_examined: 96
SET timestamp=1387199997;
DELETE FROM messages WHERE clientid='100';
[...]
# Query_time: 0.000178  Lock_time: 0.000054 Rows_sent: 0  Rows_examined: 96
SET timestamp=1387199998;
DELETE FROM messages WHERE clientid='14';

所以我猜他们确实有一个非常小的延迟,但它在MySQL中有任何有意义的意义吗?我的意思是,在“现实生活”中,0.0003可能完全被忽略,因为它的意义不大,对于MySQL和大约10ms ping的连接可以说同样吗?

1 个答案:

答案 0 :(得分:2)

我遇到了类似的问题。

有几个问题:首先,未交付的消息应该在系统中停留多长时间?永远?一天?十秒钟?

其次,错误删除未送达邮件的后果是什么?它是否会导致全球银行体系崩溃?是否会导致医院患者无法接受所需的注射?或者后续消息是否只包含丢失的消息?

最好的情况是停留时间短,错误后果低。如果错误结果很高,那么这一切都不是明智的。

为我设置解决方案需要几个步骤。

首先,编写一些代码以从消息表中获取最大ID。

 SELECT MAX(message_id) AS max_message_id FROM message

然后,一小时后,或十秒钟,或一天,或其他任何内容,删除所有ID编号小于上一次运行记录的邮件。

 DELETE FROM message WHERE message_id <= ?max_message_id

如果一切正常,则无法删除任何内容。但是,如果你有一堆陈旧的消息给一个已经走了很久的客户,那么他们就不见了。

最后,在将其投入生产之前,请等待系统中的安静时刻,并且只需发出一次命令

  TRUNCATE TABLE message

清除表中的任何旧垃圾。

您可以通过创建一个小的一行一列表来存储max_message_id,从而对事件(MySQL数据库中存储的作业)执行此操作。

修改

您还可以更改表以添加message_time列,以便在插入行时自动设置它。在您的系统安静的时候发出这三个语句,您可以负担丢弃所有现存的消息。

   TRUNCATE TABLE message; 
   ALTER TABLE message ADD COLUMN message_time TIMESTAMP 
                                  NOT NULL 
                                  DEFAULT CURRENT_TIMESTAMP;
   ALTER TABLE message ADD INDEX message_time (message_time);

然后您可以使用单个语句来清除旧记录,如此。

   DELETE FROM message WHERE message_time <=  NOW() - INTERVAL 1 HOUR

(或任何适当的间隔)。你肯定应该改变一个空的或几乎为空的表,因为它需要时间来改变很多行。

这是一个很好的解决方案,因为您可能根本不必更改消息处理客户端代码。 (当然,如果你在任何地方SELECT *,你可能需要改变它。专业提示:永远不要在应用程序代码中使用SELECT *。)