从表中删除数据行后,MySQL InnoDB无法释放磁盘空间


140

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

有什么办法可以从MySQL回收磁盘空间?

我处境很糟;该应用程序在大约50个不同的位置运行,现在几乎所有位置都出现磁盘空间不足的问题。


也运行优化命令后,ibdata1文件的大小没有减小。
Sumit Deo

4
我认为最好将该评论编辑成您的答案,然后将其删除
Ben Millwood 2012年

stackoverflow.com/q/11751792/82114的可能重复项 (但这是第一个)
FlipMcF

1
“在运行优化表命令后,ibdata1文件的大小也未减小”,这是因为您innodb_file_per_table的电源已关闭。好消息是,此选项on在MySQL的最新版本中默认为。
会计师▸

我运行“优化表xxxx”,并收到消息“表不支持优化,而是进行重新创建+分析”。在外壳上运行“ du -h / var / lib / mysql”之后,我可以看到数据库缩小了。
user1097111

Answers:


137

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

一种替代方法是配置服务器以使用innodb_file_per_table,但这将需要备份,删除数据库并还原。积极的一面是该表的.ibd文件在optimize table。之后被减少。


4
关于InnoDB每表文件模式状态的MySQL 5.5文档 “要为现有表利用[InnoDB每表文件]功能,您可以打开每表文件设置并ALTER TABLE t ENGINE=INNODB在现有表上运行。 ” 这意味着您可以打开此功能,使用ALTER TABLE命令“转换”现有表以使用单独的InnoDB文件,然后优化表以缩小其大小。但是,一旦完成,就必须弄清楚如何删除(巨大的)源InnoDB文件……
2014年

9
我猜这从技术上来说可以回答这个问题,但是我希望大多数搜索此主题的人都在寻找缩小/回收空间的实际过程,而这个问题并未提供。
Manachi

@Manachi的过程是“配置服务器以使用innodb_file_per_table”,“备份”服务器,“删除数据库”,停止mysql,删除.ibd,启动服务器并还原数据库。使用MySQL 5.5+,您可以使用Josh所说的,在更改所有表之后,停止服务器,删除巨大的.ibd,然后重新启动。
Leonel Martins

39

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

发生的是,即使删除数据库,innodb仍不会释放磁盘空间。我必须导出,停止mysql,手动删除文件,启动mysql,创建数据库和用户,然后导入。谢天谢地,我只有200MB的行,但它保留了250GB的innodb文件。

设计失败。


10
是的,那绝对是失败的。
trusktr

1
MySql 5.5有相同的问题:我运行“优化表”以减少28GB表的磁盘使用率。该操作可能试图对原始副本进行优化,然后用完分区上的所有空间。现在“优化表”失败了,即使我删除了整个数据库,分区上也没有空间了……非常令人失望。
basilikode

1
四年多以后,我遇到了与MySQL相同的问题。MS SQL是相似的:dba.stackexchange.com/questions/47310/...
乔鲍托特

24

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

“操作方法非常深入-但我在下面粘贴了相关部分。

确保在转储中还保留架构的副本。

当前,您不能从系统表空间中删除数据文件。要减小系统表空间大小,请使用以下过程:

使用mysqldump转储所有InnoDB表。

停止服务器。

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

删除InnoDB表的所有.frm文件。

配置一个新的表空间。

重新启动服务器。

导入转储文件。


感谢您包含这些步骤-避免了“如何”链接不再包含此信息
2015年

3

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

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

就这些 :)


1

解决空间回收问题的另一种方法是,在表中创建多个分区-基于范围的分区,基于值的分区,然后删除/截断该分区以回收空间,这将释放存储在特定分区中的整个数据所使用的空间。

当您为表引入分区时,表架构将需要一些更改,例如-唯一键,包含分区列的索引等。


0

一年前,我在mysql5.7版本上也遇到了同样的问题,而ibdata1占用了150 Gb。所以我添加了撤消表空间

进行Mysqldump备份
停止mysql服务
从data dir中删除所有数据
在当前my.cnf中的undo tablespace参数下面添加

 #undo tablespace
  innodb_undo_directory =  /var/lib/mysql/
  innodb_rollback_segments = 128 
  innodb_undo_tablespaces = 3
  innodb_undo_logs = 128  
  innodb_max_undo_log_size=1G
  innodb_undo_log_truncate = ON

启动mysql服务
存储mysqldump备份

问题解决了!


-1

从MySQL Inodb引擎的表中删除数据后,有几种回收磁盘空间的方法

如果您从一开始就不使用innodb_file_per_table,那么转储所有数据,删除所有文件,重新创建数据库并再次导入数据是唯一的方法(请检查上面FlipMcF的答案)

如果您使用的是innodb_file_per_table,则可以尝试

  1. 如果可以删除所有数据,则truncate命令将为您删除数据并回收磁盘空间。
  2. Alter table命令将删除并重新创建表,以便可以回收磁盘空间。因此,在删除数据后,运行不更改任何内容的更改表以释放硬键(即:表TBL_A具有字符集uf8,在删除数据后运行ALTER TABLE TBL_A字符集utf8->此命令不会更改表中的任何内容,但是它使mysql重新创建表并重新获得磁盘空间
  3. 像TBL_A一样创建TBL_B。将要保留的选择数据从TBL_A插入到TBL_B。删除TBL_A,并将TBL_B重命名为TBL_A。如果TBL_A和需要删除的数据很大,则这种方法非常有效(MySQL innodb中的delete命令的性能非常差)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.