我刚刚发现一些非常奇怪的东西,我希望有人可以向我解释。我在Linux虚拟服务器上有一个带有InnoDB表的MySQL 5.5.58数据库。其中一个表称为stats_archive
,在普通用法中是只写的:它永远不会被读取或删除。其内容纯粹为了法律合规目的而保留一段时间,每月的cronjob应删除旧条目。不幸的是,cronjob无声地失败,因此桌子被允许变得过大。今天早上我试图删除数据:
master:~# du -sh /var/lib/mysql
6.3G /var/lib/mysql
master:~# mysql -u root -p
mysql> select count(*) from stats_archive;
+-----------+
| count(*) |
+-----------+
| 26339050 |
+-----------+
1 row in set (39.40 sec)
mysql> delete from stats_archive where archive_date < '2018-01-01';
Query OK, 24628026 rows affected (7 min 17.61 sec)
master:~# du -sh /var/lib/mysql
7.4G /var/lib/mysql
正如您所看到的,MySQL使用的存储空间增长了1GB多一点。当我这样做时,没有其他明显的数据库活动。删除操作未在未提交的事务中完成,因此如果我回滚,数据库仍然不能保留它。
额外1GB的空间(不出所料)被/var/lib/mysql/ibdata1
使用了,据我所知,这个文件永远不会缩小,所以I'm stuck with it until I can do something major就像删除我的所有数据库一样,从备份中恢复并设置{{ 1}}(目前还没有)。我会在适当的时候这样做。
但我真正想知道的是为什么会发生这种情况,每次从数据库中删除行都会发生同样的情况?
注意:这是不重复this question。这个问题是关于存储没有被释放,这在InnoDB中是众所周知的,与question I linked to基本相同。我的问题是删除导致存储使用量显着增加增长。
答案 0 :(得分:2)
即使从中删除记录,InnoDB表的大小确实会增长。根本原因是InnoDB不会释放的已知事实(或错误),也不会回收已删除记录使用的空间。
为了支持事务功能(回滚,一致读取等),InnoDB使用multi-versioning,这意味着它可以维护同一记录的多个版本。多个版本存储在InnoDB表空间的undo log部分中。撤消日志部分可以无限增长。
由于删除数据也是一种修改,因此先前版本的记录存储在撤消日志部分中,导致文件大小显着增加。
答案 1 :(得分:2)
(Shadow对为什么给出了很好的解释;我会谈论现在要做什么。)
最好的办法是将表PARTITION
按周或数月(无论什么都有意义,然后导致20-60个分区)。然后是DROP PARTITION
,而不是慢得多DELETE
。并REORGANIZE PARTITION
获取新分区。更多详情here。
更好的方法,在你刚才的情况下是复制行保持。这是因为你只保留了10%的行;新表会小得多。有关如何进行create-copy-rename的更多讨论,请参阅here。
与此同时,您可以(花费几分钟的时间将桌子捆起来),通过OPTIMIZE TABLE
进行清理。如果您不喜欢将其绑定,请执行上面的create-copy-rename。