MySQL InnoDB在从表中删除数据行后没有释放磁盘空间

Sum*_*Deo 127 mysql innodb delete-row

我有一个使用InnoDB存储引擎的MySQL表; 它包含大约2M个数据行.当我从表中删除数据行时,它没有释放分配的磁盘空间.运行optimize table命令后,ibdata1文件的大小也没有减少.

有没有办法从MySQL回收磁盘空间?

我情况很糟糕; 这个应用程序在大约50个不同的位置运行,现在几乎所有这些都出现了磁盘空间不足的问题.

Leo*_*ins 132

MySQL不会减小ibdata1的大小.永远.即使您optimize table用来释放已删除记录中使用的空间,它也会在以后重用它.

另一种方法是配置要使用的服务器innodb_file_per_table,但这需要备份,删除数据库和还原.积极的一面是,在表之后,表的.ibd文件减少了optimize table.

  • 我想这在技术上回答了这个问题,但我希望搜索这个主题的大多数人都在寻找收缩/回收空间的实际过程,这个答案没有提供. (7认同)
  • [关于InnoDB文件每表模式状态的MySQL 5.5文档](http://dev.mysql.com/doc/refman/5.5/en/innodb-multiple-tablespaces.html)"利用[InnoDB文件] -per-table]现有表的功能,您可以打开每表文件设置并在现有表上运行`ALTER TABLE t ENGINE = INNODB`.这意味着您可以启用此功能,"转换"现有表以使用带有ALTER TABLE命令的单独InnoDB文件,然后优化表以缩小其大小.但是,一旦你完成了,你必须弄清楚如何删除(巨大的)源InnoDB文件...... (4认同)

gil*_*ilm 37

我自己也遇到了同样的问题.

会发生什么,即使你删除数据库,innodb仍然不会释放磁盘空间.我不得不导出,停止mysql,手动删除文件,启动mysql,创建数据库和用户,然后导入.感谢上帝,我只有200MB的行,但它没有250GB的innodb文件.

设计失败.

  • 是的,那肯定是失败的. (9认同)
  • 4 年多后,我遇到了与 MySQL 相同的问题。MS SQL 类似:https://dba.stackexchange.com/questions/47310/shrinkfile-best-practices-and-experience (3认同)
  • MySql 5.5 有同样的问题:我运行“优化表”以减少 28GB 表的磁盘使用量。该操作可能试图对原始副本进行优化克隆,并且这样做会耗尽分区上的所有空间。现在“优化表”失败了,即使我删除了整个数据库,我的分区上也没有空间......非常令人失望。 (2认同)

Fli*_*McF 23

如果您不使用innodb_file_per_table,则可以回收磁盘空间,但是相当繁琐,并且需要大量的停机时间.

如何为深入漂亮-但我粘贴下面的相关部分.

确保还在转储中保留模式的副本.

目前,您无法从系统表空间中删除数据文件.要减小系统表空间大小,请使用以下过程:

使用mysqldump转储所有InnoDB表.

停止服务器.

删除所有现有的表空间文件,包括ibdata和ib_log文件.如果要保留信息的备份副本,请在删除MySQL安装中的文件之前将所有ib*文件复制到另一个位置.

删除InnoDB表的任何.frm文件.

配置新的表空间.

重启服务器.

导入转储文件.

  • 感谢您提供这些步骤 - 因为“如何”链接不再包含此信息 (2认同)

Ske*_*tor 14

我发现的最短方法是:

\n
ALTER TABLE YOURTABLE ENGINE=InnoDB\n
Run Code Online (Sandbox Code Playgroud)\n

截断或删除不需要的记录后,我运行了此命令,表空间缩小了。

\n

这是 Shlomi Noach 写的一篇不错的文章,我在那里找到了(这篇文章和更多相关信息)。

\n

感谢什洛米·诺奇。希望能帮助到你。以防万一我也将其粘贴到这里:

\n

使用 InnoDB 时,您有两种管理表空间存储的方法:

\n

将所有内容放入一个大文件中(可以选择拆分)。\n每个表一个文件。\n我将讨论这两个选项的优缺点,并努力说服 innodb_file_per_table 更可取。

\n

单个表空间

\n

将所有内容放在一个大文件中意味着所有方案中的所有表和索引都位于该文件中 \xe2\x80\x98mixed\xe2\x80\x99 中。

\n

这允许以下良好的属性:可以在不同的表和不同的方案之间共享可用空间。因此,如果我从日志表中清除许多行,则现在未使用的空间可能会被任何其他表的新行占用。

\n

这个同样好的属性也转化为一个不太好的属性:数据在表空间中可能会出现很大的碎片。

\n

InnoDB\xe2\x80\x99s 表空间的一个恼人的特性是它们永远不会收缩。因此,从日志表中清除这些行后,表空间文件(通常是 ibdata1)仍然保留相同的存储。它不会释放文件系统的存储空间。

\n

我\xe2\x80\x99不止一次地看到某些表是如何无人监视的,不断增长,直到磁盘空间达到90%,并且短信通知开始到处发出蜂鸣声。

\n

在这种情况下,\xe2\x80\x99 没什么可做的。好吧,人们总是可以清除行。当然,该空间将被 InnoDB 重用。但是,拥有一个消耗大约 80-90% 磁盘空间的文件会带来性能灾难。这意味着盘针需要移动很大的距离。整体磁盘性能运行非常低。

\n

解决此问题的最佳方法是设置一个新的从站(清除行后),并将数据转储到该从站中。

\n

InnoDB热备份

\n

有趣的是,ibbackup 实用程序将按原样复制表空间文件。如果是 120GB,其中仅使用了 30GB,您仍然可以获得 120GB 的备份和恢复。

\n

mysqldump、mk-并行转储

\n

如果您只有原始机器可以使用,mysqldump 将是您的最佳选择。假设您\xe2\x80\x99仅使用InnoDB,则使用\xe2\x80\x93单事务转储即可完成这项工作。或者您可以利用 mk-parallel-dump 来加快速度(取决于您的转储方法和可访问性需求,请注意锁定)。

\n

innodb_file_per_table

\n

设置此参数后,将为每个表创建一个 .ibd 文件。我们得到的是这样的:

\n

表空间不在不同的表之间共享,当然也不在不同的方案之间共享。\n每个文件都被视为自己的表空间。\n同样,表空间的大小永远不会减少。\n可以重新获得每个表空间的空间。\n等等。最后两个似乎是冲突的,不是\xe2\x80\x99吗?让\xe2\x80\x99s 解释一下。

\n

在我们的日志表示例中,我们清除了许多行(最多删除 90GB 的数据)。.ibd 文件不会缩小。但我们可以这样做:

\n

更改表日志引擎=InnoDB

\n

将会发生的是创建一个新的临时文件,并在其中重建表。仅现有数据会添加到新表中。完成后,原始表将被删除,新表将重命名为原始表。

\n

当然,这需要很长时间,在此期间表被完全锁定:不允许写入和读取。但仍然 \xe2\x80\x93 它允许我们重新获得磁盘空间。

\n

使用新的 InnoDB 插件,执行 TRUNCATE TABLE 日志语句时也会重新获得磁盘空间。

\n

碎片并不像单个表空间那样糟糕:数据被限制在较小文件的边界内。

\n

监控

\n

innodb_file_per_table 的另一个好处是可以在文件系统级别监视表大小。您不需要访问 MySQL、使用 SHOW TABLE STATUS 或查询 INFORMATION_SCHEMA。您可以在 MySQL 数据目录(和子目录)下查找前 10 个最大的文件,并监控它们的大小。您可以看到哪个表增长最快。

\n

备份

\n

最后,还无法通过复制 .ibd 文件来备份单个 InnoDB 表。但希望工作能够朝着这个方向进行。

\n


小智 7

十年后,我遇到了同样的问题。我通过以下方式解决了它:

  • 我优化了所有的数据库。
  • 我在服务上重新启动了我的计算机和 MySQL (Windows+r --> services.msc)

就这些 :)

  • 是的,只需“优化表 tbl_name;” 并重启mysql (2认同)

小智 6

今天遇到了这个问题(问题最初提出 11 年后),并能够通过删除表并再次创建它来修复它。我不必重新安装数据库或转储和恢复、修改存储、更改表空间等 - 都没有。

我使用的是 InnoDB,但不是 innodb_file_per_table,所以即使我从表中删除了 900K 行,数据库大小也没有改变。所以我删除了该表并重新创建了它。

就我而言,我的表被清理为零行,因此我很容易删除表,但保留我运行的结构

create table mynewtable as select * from myoldtable where 1=2;
Run Code Online (Sandbox Code Playgroud)

其次是

drop table myoldtable;
Run Code Online (Sandbox Code Playgroud)

这将我的数据库大小从 5G 减少到 400MB

  • 欢迎来到堆栈溢出。数据库的本质是,由于删除的记录,数据不会释放回系统。根据我的研究,INNODB 没有像某些数据库那样的回收资源命令或类似命令。不过,就您而言,我很想尝试 TRUNCATE TABLE myoldtable; ...我希望这将是一个更简单的解决方案。 (2认同)
  • SQL 创建表 mynewtable as select * from myoldtable where 1=2; 不会创建完全相同的表,主键等会丢失。最好做一个 show create table myoldtable; 然后根据显示的内容创建一个新表。 (2认同)

sNI*_*sss 5

对于 InnoDB。你可以尝试这个方法。

  1. 根据这篇文章。

    更改表 tbl_name 引擎 = INNODB;

  2. 然后刷新information_schema中的表大小和索引信息。

    分析表 tbl_name;