如何从单列清除大型MySQL数据库旧条目?

时间:2016-05-26 13:36:24

标签: mysql pagination sql-update

我需要删除旧的数据库条目有效负载,同时保留相同条目的其他数据(id和其他属性)。 有问题的表有 message_id 列(包含与其他信息连接的日期戳), content 列(BLOB,它占数据库总大小的90%以上)以及在这种情况下我们没有用的其他一些列。

我首先尝试使用条件运行简单更新:

UPDATE LOW_PRIORITY repository SET content="" WHERE SUBSTR( message_id, 6, 6 )<201601 AND message_box = "IN";

我从每个条目message_id中提取 YYYYMM ,如果它比选定的截止月份更早 - 我将 content 替换为空字符串。

数据库大小超过25GB,在我的表中保存了近2KK条目,并且运行在非常适中的硬件上,运行一段时间后我的查询失败并出现错误:

ERROR 2013 (HY000): Lost connection to MySQL server during query

通常我会尽量避免更改数据库变量,但是我知道当你尝试从大型转储文件恢复数据库时会弹出这个错误,因此我去更新设置以处理100MB数据包大小:

set global max_allowed_packet=104857600;

重新运行我的UPDATE查询导致了一个新错误:

ERROR 2013 (HY000): Lost connection to MySQL server during query

正如我之前提到的 - 我的MySQL服务器运行在一个非常适度的硬件上,我宁愿不修改可能使服务器超出可用资源的设置,因此而不是增加所有可用的超时数据库变量,我决定使用这样的查询在较小的块中运行我的查询:

UPDATE LOW_PRIORITY repository SET content="" WHERE message_id in (select message_id from(select message_id from repository where SUBSTR( message_id, 6, 6 )<201603 AND message_box = "IN" limit 0, 1000)as temp);

此查询失败并显示错误:

ERROR 1206 (HY000): The total number of locks exceeds the lock table size

当限制为“限制1”的单行时,它也会因同一查询而失败!

我是否错误地使用了分页,还是有其他更好的方式来执行此操作?

* DB运行的虚拟Ubuntu服务器具有双核Intel CPU,1GB RAM和100GB HDD。我不完全适合它的日常任务,我真的不想仅为这一个查询增加规格。

2 个答案:

答案 0 :(得分:1)

你试图以复杂的方式欺骗​​mysql做一些它不想要的东西(在limit语句中使用in)(复杂=更多资源)。这没错,但你可以写

UPDATE LOW_PRIORITY repository SET content="" 
WHERE content <> ""
and SUBSTR( message_id, 6, 6 ) < 201603 AND message_box = "IN" 
limit 1000;

这将更新仍有内容的前1000行。

答案 1 :(得分:0)

我认为你的#1问题是你的WHERE条件无法在message_id字段上使用索引。

为什么不简单地做:

WHERE message_id < 20160100* ...

假设这是整数字段,201512 **将会少于201601 **,因此您的结果不会有任何变化。但是删除子字符串函数将允许您在该字段上使用索引。