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

lok*_*art 550 mysql database innodb

我在localhost中使用MySQL作为在R中执行统计的"查询工具",也就是说,每次运行R脚本时,我创建一个新数据库(A),创建一个新表(B),将数据导入B ,提交查询以获得我需要的内容,然后我删除B并删除A.

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

我使用或多或少的默认MySQL设置进行设置,有没有办法可以在一段固定的时间后自动缩小/清除ibdata1文件?

Joh*_*n P 768

ibdata1不是缩小是一个特别恼人的MySQL功能.该ibdata1文件实际上不能缩小,除非你删除所有数据库,删除文件并重新加载转储.

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

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

[mysqld]
innodb_file_per_table=1
Run Code Online (Sandbox Code Playgroud)

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

由于你想从ibdata1你那里收回空间,你实际上必须删除该文件:

  1. mysqldump的所有数据库,过程,触发器等,除了mysqlperformance_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/en/drop-database.html

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

通过使用该命令ALTER TABLE <tablename> ENGINE=innodb,OPTIMIZE TABLE <tablename>可以从ibdata1中提取数据和索引页面以分离文件.但是,除非您执行上述步骤,否则ibdata1不会缩小.

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

  • 那么information_schema和performance_schema呢? (15认同)
  • @JordanMagnuson不要费心去掉information_schema.它实际上只是一堆只读视图,而不是表.并且没有与它们相关联的文件.甚至没有数据库的目录.informations_schema正在使用内存db-engine,并在mysqld停止/重启时被删除并重新生成.请参阅http://dev.mysql.com/doc/refman/5.5/en/information-schema.html.关于performance_schema我自己没有使用过该模式. (15认同)
  • 我不知道这是否是最近的事情,但是一旦启用了innodb_file_per_table选项,您就可以简单地运行"ALTER TABLE <tablename> ENGINE = InnoDB"(即使它已经是InnoDB),它会将表移动到其单个文件中.无需删除数据库等. (4认同)
  • +1 FWIW,MySQL 5.6默认启用`innodb_file_per_table`. (3认同)
  • 是的,ibdata1预计将与其他文件一起出现.ibdata1文件仍将保存有关表,撤消日志和缓冲区的元数据. (3认同)

Vin*_*ula 45

加入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_logfile0,ib_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以涵盖您希望保留的所有数据库.

  • 对于每个拥有InnoDB表的数据库,您需要重复1,2和6. (6认同)
  • 在#5和#6之间需要更多步骤.您必须重新创建数据库并重新分配权限.所以从mysql客户端命令提示符`创建数据库database_name;`然后`将所有关于database_name.*的权限授予'username'@'localhost'由'password'标识;` (4认同)
  • 要在“密码:”提示下键入密码(这是一种更安全的做法),只需将“ -p”放在没有任何实际密码的地方。 (2认同)
  • 现在这会导致错误`InnoDB: File ./ibdata1: 'open' returned OS error 71.Cannot continue operation`,因此无法重新启动服务器! (2认同)

tit*_*boa 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


Vik*_*Vik 14

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

我想你可以找到很好的解释和解决方案:

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


Sla*_*lam 11

似乎没有人提到innodb_undo_log_truncate设置可能产生的影响。

在阅读了Percona 关于该主题的博客文章后,我在 MariaDB 10.6 中启用了UNDO LOG填充 95% 的条目截断ibdata1,并且在完全删除和恢复之后,从那一刻起我的条目ibdata1再也没有增长过。

在默认情况下,innodb_undo_log_truncate = 0ibdata1很容易达到数据库空间占用的 10%,也就是几十 GB。

使用 时innodb_undo_log_truncate = 1ibdata1它的大小固定为 76 Mb。


Pie*_*hac 10

在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
Run Code Online (Sandbox Code Playgroud)

另存为purge_binlogs.sh并运行root.

不包括mysql,information_schema,performance_schema(和binlog目录).

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

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

PURGE BINARY LOGS BEFORE CURRENT_TIMESTAMP;
Run Code Online (Sandbox Code Playgroud)


小智 6

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

MySQL> 5.1.24:

mysqlshow --status myInnodbDatabase myTable | awk '{print $20}'
Run Code Online (Sandbox Code Playgroud)

MySQL <5.1.24:

mysqlshow --status myInnodbDatabase myTable | awk '{print $35}'
Run Code Online (Sandbox Code Playgroud)

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

du -b ibdata1
Run Code Online (Sandbox Code Playgroud)

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


小智 5

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

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