我刚刚观察到一些非常奇怪的事情,我希望有人可以向我解释。我在 Linux 虚拟服务器上有一个 MySQL 5.5.58 数据库,其中包含 InnoDB 表。其中一张表被调用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
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,MySQL 使用的存储增长了 1GB 多一点。当我执行此操作时,没有其他明显的数据库活动。删除不是在未提交的事务中完成的,因此数据库不应该仍然保留它以防我回滚。
额外的 1GB 空间(毫不奇怪)已被使用/var/lib/mysql/ibdata1,据我所知,该文件永远不会缩小,所以我一直坚持使用它,直到我可以做一些重大的事情,例如删除所有数据库,从备份恢复和设置innodb_file_per_table=1(它是目前不是)。我会在适当的时候这样做。
但我真正想知道的是为什么会发生这种情况,每次我从数据库中删除行时都会发生同样的情况吗?
注意:这不是这个问题的重复。这个问题是关于存储未释放的问题,这在 InnoDB 中是众所周知的,并且与我链接到的问题本质上相同。我的问题是关于删除导致存储使用量显着增长。
(Shadow 很好地解释了原因;我将讨论现在该做什么。)
最好的做法是以PARTITION周或月为单位(无论什么合理并导致 20-60 个分区)。然后DROP PARTITION反而慢得多DELETE。并REORGANIZE PARTITION获得一个新的分区。更多详细信息请参见此处。
在您刚刚遇到的情况下,更好的方法是复制要保留的行。这是因为您只保留 10% 的行;新桌子会小得多。有关如何执行创建复制重命名的更多讨论,请参阅此处。
同时,您可以(花费几分钟的时间来收拾桌子)通过执行以下操作来清理它OPTIMIZE TABLE。如果您不喜欢将其捆绑在一起,请执行上面的创建-复制-重命名操作。