关于数据库:如何在MySQL中收缩/清除ibdata1文件

How to shrink/purge ibdata1 file in MySQL

我在localhost中使用mysql作为在r中执行统计的"查询工具",也就是说,每次运行r脚本时,我都会创建一个新的数据库(a),创建一个新的表(b),将数据导入b,提交一个查询以得到我需要的,然后我删除b和drop a。

它对我来说很好,但是我意识到ibdata文件的大小在快速增长,我在mysql中没有存储任何东西,但是ibdata1文件已经超过了100MB。

我正在或多或少地使用默认的mysql设置,是否有一种方法可以在固定的时间段后自动收缩/清除ibdata1文件?


ibdata1没有收缩是MySQL的一个特别恼人的特性。除非删除所有数据库、删除文件并重新加载转储,否则无法实际收缩ibdata1文件。

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

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

1
2
[mysqld]
innodb_file_per_table=1

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

当您想从ibdata1中回收空间时,实际上必须删除该文件:

  • 对除mysqlperformance_schema数据库外的所有数据库、过程、触发器等执行mysqldump操作。
  • 删除除上述2个数据库以外的所有数据库
  • 停止MySQL
  • 删除ibdata1ib_log文件
  • 启动MySQL
  • 从转储还原
  • 在步骤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 ENGINE=innodbOPTIMIZE TABLE 可以从ibdata1中提取数据和索引页以分离文件。但是,除非执行上述步骤,否则IBdata1不会收缩。

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


    加上约翰·P的回答,

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

  • mysqldump -u [username] -p[root_password] [database_name] >
    dumpfilename.sql
  • 江户十一〔一〕号
  • 埃多克斯1〔2〕
  • 埃多克斯1〔3〕江户十一〔四〕号(并删除可能命名为ib_logfile0ib_logfile1等的任何其他ib_日志文件…)
  • 江户十一〔七〕号
  • 埃多克斯1〔8〕
  • 埃多克斯1〔9〕
  • 警告:如果此MySQL实例上有其他数据库,这些说明将导致您丢失其他数据库。确保修改步骤1、2和6、7以涵盖您希望保留的所有数据库。


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

    如何收缩现有的ibdata文件:

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

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

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

    有关多个表空间的详细信息:

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


    If you use the InnoDB storage engine for (some of) your MySQL tables, you’ve probably already came across a problem with its default configuration. As you may have noticed in your MySQL’s data directory (in Debian/Ubuntu – /var/lib/mysql) lies a file called ‘ibdata1′. It holds almost all the InnoDB data (it’s not a transaction log) of the MySQL instance and could get quite big. By default this file has a initial size of 10Mb and it automatically extends. Unfortunately, by design InnoDB data files cannot be shrinked. That’s why DELETEs, TRUNCATEs, DROPs, etc. will not reclaim the space used by the file.

    我认为你可以找到很好的解释和解决办法:

    MySQL: Reducing ibdata1


    在bash中快速编写接受答案的过程脚本:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #!/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目录中。

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


    如果您的目标是监视MySQL的可用空间,并且您不能停止MySQL来收缩您的ibdata文件,那么可以通过table status命令来获取它。例子:

    mysql>5.1.24:

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

    mysql<5.1.24:

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

    然后将该值与IBDATA文件进行比较:

    1
    du -b ibdata1

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


    在新版本的mysql服务器中,上面的食谱将粉碎"mysql"数据库。在旧版本中,它起作用。在新的一些表中,切换到表类型innodb,这样做会损坏它们。最简单的方法是转储所有数据库,卸载mysql服务器,加载项保留my.cnf:

    1
    2
    3
    4
    5
    6
    7
    [mysqld]
    innodb_file_per_table=1


    erase all in /var/lib/mysql
    install mysql-server
    restore users and databases

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

    使用autoextend(可能是最常见的大小设置)IBdata1预分配存储,每次几乎满时都会增长。这使得写入速度更快,因为已经分配了空间。

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

    所以只有当你真正需要这些数据的时候,它才会继续增长。除非您实际需要另一个应用程序的空间,否则可能没有理由缩小它。