如何在MySQL中缩小/清除ibdata1文件


561

我在localhost中将MySQL用作在R中执行统计信息的“查询工具”,也就是说,每次运行R脚本时,我都会创建一个新的数据库(A),创建一个新的表(B),然后将数据导入B ,提交查询以获取所需信息,然后删除B并删除A。

对我来说,它工作正常,但是我意识到ibdata文件的大小正在迅速增加,我没有在MySQL中存储任何内容,但是ibdata1文件已超过100 MB。

我在设置中使用了或多或少的默认MySQL设置,是否可以在固定的时间后自动收缩/清除ibdata1文件?


Answers:


777

ibdata1并没有减少,这是MySQL的一个特别令人讨厌的功能。该ibdata1文件实际上不能缩小,除非你删除所有数据库,删除文件并重新加载转储。

但是您可以配置MySQL,以便将每个表(包括其索引)存储为单独的文件。这样ibdata1就不会增长那么大。根据Bill Karwin的评论,默认情况下从MySQL 5.6.6版本开始启用此功能。

不久前我做了这个。但是,要将服务器设置为对每个表使用单独的文件,您需要进行更改my.cnf才能启用此功能:

[mysqld]
innodb_file_per_table=1

http://dev.mysql.com/doc/refman/5.5/en/innodb-multiple-tablespaces.html

当您要回收空间时,ibdata1实际上必须删除文件:

  1. 数据库以外的mysqldump所有数据库,过程,触发器等执行amysqlperformance_schema
  2. 删除除上述2个数据库以外的所有数据库
  3. 停止mysql
  4. 删除ibdata1ib_log文件
  5. 启动mysql
  6. 从转储还原

当您在步骤5中启动MySQL时,ibdata1ib_log文件将被重新创建。

现在您可以出发了。创建新数据库进行分析时,这些表将位于单独的ibd*文件中,而不是中ibdata1。由于通常在不久之后ibd*删除数据库,因此文件将被删除。

http://dev.mysql.com/doc/refman/5.1/zh-CN/drop-database.html

您可能已经看到了:http :
//bugs.mysql.com/bug.php?id=1341

通过使用该命令ALTER TABLE <tablename> ENGINE=innodbOPTIMIZE TABLE <tablename>一个命令,可以将数据和索引页面从ibdata1提取到单独的文件。但是,除非执行上述步骤,否则ibdata1将不会收缩。

关于information_schema,这是不必要的,也没有可能删除。实际上,它只是一堆只读视图,而不是表。而且没有与之关联的文件,甚至没有数据库目录。在informations_schema使用内存数据库引擎和被丢弃,一旦停止再生/重启mysqld的。参见https://dev.mysql.com/doc/refman/5.7/en/information-schema.html


16
@JordanMagnuson不要费心丢掉information_schema。实际上,它只是一堆只读视图,而不是表。并且没有与之关联的文件。甚至没有数据库的目录。informations_schema正在使用内存db-engine,并在mysqld停止/重新启动时删除并重新生成。参见dev.mysql.com/doc/refman/5.5/en/information-schema.html。关于performance_schema,我自己没有使用过该架构。
约翰·P

4
我不知道这是否是最近的事情,但是一旦启用了innodb_file_per_table选项,您就可以简单地运行“ ALTER TABLE <tablename> ENGINE = InnoDB”(即使它已经是InnoDB)并将其移入其单独的文件中。无需删除数据库等。
CR。

3
+1 FWIW,MySQL 5.6 innodb_file_per_table默认启用。
Bill Karwin 2013年

3
是的,ibdata1应该和其他文件一起存在。ibdata1文件仍将保留有关表,撤消日志和缓冲区的元数据。
约翰·P

1
由于ibdata1文件,我的服务器空间不足,所以我什至无法转储数据库。将文件移动到/ var / lib / mysql(“ mysql”,“ ibdata1”,“ ib_logfile0”和“ ib_logfile1”除外)上是否相同,然后按照以下步骤进行操作?见stackoverflow.com/questions/2482491/...
Sophivorus

47

除了John P的答案

对于Linux系统,可以使用以下命令来完成步骤1-6:

  1. mysqldump -u [username] -p[root_password] [database_name] > dumpfilename.sql
  2. DROP DATABASE [database_name];
  3. sudo /etc/init.d/mysqld stop
  4. sudo rm /var/lib/mysql/ibdata1
    sudo rm /var/lib/mysql/ib_logfile (并删除可能名为的任何其他ib_logfile ib_logfile0ib_logfile1等等。)
  5. sudo /etc/init.d/mysqld start
  6. create database [database_name];
  7. mysql -u [username]-p[root_password] [database_name] < dumpfilename.sql

警告:如果此mysql实例上有其他数据库,则这些说明将导致您丢失其他数据库。确保已修改步骤1,2和6,7,以覆盖您希望保留的所有数据库。


6
对于具有InnoDB表的每个数据库,您需要重复1,2和6。
2014年

4
在#5和#6之间,您还需要几个步骤。您必须重新创建数据库并重新分配权限。因此,从MySQL客户端的命令提示符create database database_name;,然后grant all privileges on database_name.* to 'username'@'localhost' identified by 'password';
弗雷德

1
@fred在执行此操作时,我不需要授予特权。可能是因为我用相同的名称重新创建了数据库吗?
crmpicco

2
要在Password:提示符下键入密码(这是一种更安全的做法),只需输入-p没有任何实际密码的密码即可。
ADTC

除非您告诉mysqldump这样做,否则不会转储触发器,事件和例程/函数。如果您的任何数据库包含--triggers,--events和--routines,则也要添加它们。此外,只需使用--all-databases转储即可一次转储所有数据库,而不是一个接一个地转储。
Friek

34

当您删除innodb表时,MySQL不会释放ibdata文件中的空间,这就是它不断增长的原因。这些文件几乎不会缩小。

如何缩小现有的ibdata文件:

http://dev.mysql.com/doc/refman/5.5/en/innodb-resize-system-tablespace.html

您可以对此进行脚本编写,并安排脚本在固定时间段后运行,但是对于上述设置,似乎多个表空间是一个更简单的解决方案。

如果使用配置选项innodb_file_per_table,则会创建多个表空间。也就是说,MySQL为每个表创建单独的文件,而不是一个共享文件。这些单独的文件存储在数据库的目录中,并且在删除该数据库时将其删除。在您的情况下,这应该不需要收缩/清除ibdata文件。

有关多个表空间的更多信息:

http://dev.mysql.com/doc/refman/5.5/en/innodb-multiple-tablespaces.html


第一环断,我能找到最接近的匹配:dev.mysql.com/doc/refman/5.5/en/...
黑冰

14

如果将InnoDB存储引擎用于(某些)MySQL表,则可能已经遇到了默认配置问题。您可能已经注意到,在MySQL的数据目录(在Debian / Ubuntu – / var / lib / mysql中)中有一个名为“ ibdata1”的文件。它保存了MySQL实例的几乎所有InnoDB数据(不是事务日志),并且可能变得很大。默认情况下,此文件的初始大小为10Mb,并且会自动扩展。不幸的是,根据设计,InnoDB数据文件无法缩小。这就是为什么DELETE,TRUNCATE,DROP等不会回收文件使用的空间的原因。

我认为您可以在此处找到良好的解释和解决方案:

http://vdachev.net/2007/02/22/mysql-reducing-ibdata1/


11

用bash快速编写接受答案的程序脚本:

#!/usr/bin/env bash
DATABASES="$(mysql -e 'show databases \G' | grep "^Database" | grep -v '^Database: mysql$\|^Database: binlog$\|^Database: performance_schema\|^Database: information_schema' | sed 's/^Database: //g')"
mysqldump --databases $DATABASES -r alldatabases.sql && echo "$DATABASES" | while read -r DB; do
    mysql -e "drop database \`$DB\`"
done && \
    /etc/init.d/mysql stop && \
    find /var/lib/mysql -maxdepth 1 -type f \( -name 'ibdata1' -or -name 'ib_logfile*' \) -delete && \
    /etc/init.d/mysql start && \
    mysql < alldatabases.sql && \
    rm -f alldatabases.sql

另存为purge_binlogs.sh并运行为root

不包括mysqlinformation_schemaperformance_schema(和binlog目录)。

假设您具有管理员凭据,/root/.my.cnf并且数据库位于默认/var/lib/mysql目录中。

您还可以在运行此脚本后清除二进制日志,以通过以下方法重新获得更多磁盘空间:

PURGE BINARY LOGS BEFORE CURRENT_TIMESTAMP;

仍然不确定为什么,但是今天我的一些InnoDB表在相似的过程中已损坏,因此alldatabases.sql在仔细检查所有表是否正常之前我不会删除。至于一些改进:innodb_fast_shutdown=0在关机之前设置,autocommit=0在导入SQL文件之前设置,在导入SQL文件之后执行COMMIT并设置autocommit=1mysqlcheck --all-databases在删除备份之前使用。
维克多

6

如果您的目标是监视MySQL的可用空间,并且无法停止MySQL收缩ibdata文件,请通过表状态命令获取它。例:

MySQL> 5.1.24:

mysqlshow --status myInnodbDatabase myTable | awk '{print $20}'

MySQL <5.1.24:

mysqlshow --status myInnodbDatabase myTable | awk '{print $35}'

然后将此值与您的ibdata文件进行比较:

du -b ibdata1

资料来源:http : //dev.mysql.com/doc/refman/5.1/en/show-table-status.html


4

在新版本的mysql-server上面,配方将粉碎“ mysql”数据库。在旧版本中,它可以工作。在新表中,某些表切换为表类型INNODB,这样做会损坏它们。最简单的方法是:

  • 转储所有数据库
  • 卸载mysql服务器,
  • 添加仍然为my.cnf:
    [mysqld]
    innodb_file_per_table=1
  • 擦除/ var / lib / mysql中的所有内容
  • 安装mysql服务器
  • 恢复用户和数据库

1

如前所述,您不能收缩ibdata1(这样做需要转储和重建),但是通常也没有真正的需要。

使用自动扩展(可能是最常用的大小设置)时,ibdata1会预分配存储,并在存储空间即将满时对其进行扩展。由于已经分配了空间,因此写入速度更快。

当您删除数据时,它不会收缩,但是文件内的空间被标记为未使用。现在,当您插入新数据时,它将在文件进一步增长之前重用文件中的空白空间。

因此,如果您确实需要这些数据,它只会继续增长。除非您实际上需要另一个应用程序的空间,否则可能没有理由缩小它。


66
我认为您对释放空间的需求有点不屑一顾。
drewish

2
我有一个60Gig固态分区。因为我使用4 + gig数据库,所以空间很快用完了。我希望尽快将mysql移至另一个分区,但是此问题及其答案将在此同时为我提供帮助
NullVoxPopuli

3
感谢您的回答,它非常有帮助。我已经从旧有数据中清除了一些表...很高兴知道磁盘上的大小不会很快再次增加。
布拉德

1
我有一个500G的ibdata1文件-但现在存储在其中的几乎所有数据都存储在每个数据库文件中。我非常需要缩小这种巨大的空间浪费!
弗兰克斯特

2
废话!这一直腹胀一个文件需要被修剪不管你是空间用完或没有。我会称它为storage leak
ADTC
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.