ChatGPT解决这个技术问题 Extra ChatGPT

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

我在 localhost 中使用 MySQL 作为在 R 中执行统计的“查询工具”,也就是说,每次我运行 R 脚本时,我都会创建一个新数据库(A),创建一个新表(B),将数据导入 B ,提交查询得到我需要的,然后我丢B,丢A。

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

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


K
Kar.ma

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

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

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

[mysqld]
innodb_file_per_table=1

https://dev.mysql.com/doc/refman/5.6/en/innodb-file-per-table-tablespaces.html

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

对除 mysql 和 performance_schema 数据库之外的所有数据库、过程、触发器等进行 mysqldump 删除除上述 2 个数据库之外的所有数据库 停止 mysql 删除 ibdata1 和 ib_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 <tablename> ENGINE=innodbOPTIMIZE TABLE <tablename>,可以从 ibdata1 提取数据和索引页面到单独的文件中。但是,除非您执行上述步骤,否则 ibdata1 不会缩小。

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


@JordanMagnuson 不要费心放弃 information_schema。它实际上只是一堆只读视图,而不是表。并且没有与它们关联的文件。甚至没有数据库的目录。 informations_schema 正在使用内存数据库引擎,并在 mysqld 停止/重新启动时被删除并重新生成。请参阅dev.mysql.com/doc/refman/5.5/en/information-schema.html。关于 performance_schema 我自己没有使用过该模式。
我不知道这是否是最近发生的事情,但是一旦启用了 innodb_file_per_table 选项,您就可以简单地运行“ALTER TABLE ENGINE=InnoDB”(即使它已经是 InnoDB),它会将表移动到其单独的文件中.无需删除数据库等。
+1 FWIW,MySQL 5.6 默认启用 innodb_file_per_table
是的,ibdata1 应该与其他文件一起出现。 ibdata1 文件仍将保存有关表、撤消日志和缓冲区的元数据。
由于 ibdata1 文件,我的服务器空间已用完,因此我什至无法转储数据库。只移动 /var/lib/mysql 中的文件(“mysql”、“ibdata1”、“ib_logfile0”和“ib_logfile1”除外)然后按照步骤进行操作是否相同?请参阅stackoverflow.com/questions/2482491/…
K
Kar.ma

添加到 John P's answer

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

mysqldump -u [username] -p[root_password] [database_name] > dumpfilename.sql mysqladmin -u [username] -p[root_password] drop [database_name] sudo /etc/init.d/mysqld stop sudo rm /var/lib/ mysql/ibdata1 sudo rm /var/lib/mysql/ib_logfile* sudo /etc/init.d/mysqld start mysqladmin -u [username] -p[root_password] create [database_name] mysql -u [username] -p[root_password] [数据库名称] <转储文件名.sql

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


您需要为每个具有 InnoDB 表的数据库重复 1、2 和 6。
您需要在#5 和#6 之间再执行几个步骤。您必须重新创建数据库并重新分配权限。所以从 mysql 客户端命令提示符create database database_name; 然后 grant all privileges on database_name.* to 'username'@'localhost' identified by 'password';
@fred 这样做时我不需要授予特权。可能是因为我重新创建了同名的数据库?
要在 Password: 提示符处输入密码(这是一种更安全的做法),只需输入 -p 而无需任何实际密码。
现在这会导致错误 InnoDB: File ./ibdata1: 'open' returned OS error 71. Cannot continue operation,因此无法重新启动服务器!
C
Clément Moulin - SimpleRezo

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

如何缩小现有的 ibdata 文件:

https://dev.mysql.com/doc/refman/5.6/en/innodb-system-tablespace.html#innodb-resize-system-tablespace

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

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

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

https://dev.mysql.com/doc/refman/5.6/en/innodb-file-per-table-tablespaces.html


第一个链接断开,我能找到的最接近的匹配:dev.mysql.com/doc/refman/5.5/en/…
m
miken32

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

#!/usr/bin/env bash
dbs=$(mysql -BNe 'show databases' | grep -vE '^mysql$|^(performance|information)_schema$')
mysqldump --events --triggers --databases $dbs > alldatabases.sql && \
    echo "$dbs" | while read -r db; do
        mysqladmin drop "$db"
    done && \
    mysql -e 'SET GLOBAL innodb_fast_shutdown = 0' && \
    /etc/init.d/mysql stop && \
    rm -f /var/lib/mysql/ib{data1,_logfile*} && \
    /etc/init.d/mysql start && \
    mysql < 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,导入SQL文件前设置autocommit=0,导入SQL文件后执行COMMIT并设置autocommit=1,删除备份前使用mysqlcheck --all-databases
A
A.L

如果您将 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/


C
Cyno

如果您的目标是监控 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


B
Bahram Ardalan

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

转储所有数据库

卸载mysql服务器,

添加仍然是my.cnf:

    [mysqld]
    innodb_file_per_table=1

擦除 /var/lib/mysql 中的所有内容

安装mysql服务器

恢复用户和数据库


s
steveayre

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

使用自动扩展(可能是最常见的大小设置)ibdata1 预分配存储,每次几乎满时都会增长。由于空间已经分配,这使得写入速度更快。

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

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


我认为您对释放空间的需要有点不屑一顾。
我有一个 60Gig 固态分区。因为我使用 4+gig 数据库,所以我很快就用完了空间。我希望尽快将 mysql 移动到另一个分区,但同时这个问题及其答案将对我有所帮助
感谢您的回答,这非常有帮助。我已经从遗留数据中清除了一些表......很高兴知道磁盘上的大小不会很快再次增长。
我有一个 500G 的 ibdata1 文件 - 但几乎所有存储在其中的数据现在都存储在每个数据库文件中。我非常需要缩小这种巨大的空间浪费!
完全废话!一个不断膨胀的文件需要修剪,无论您的空间是否不足。我称之为storage leak
S
Slam

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

在阅读了有关该主题的 Percona's blog post 之后,我在 MariaDB 10.6 中启用了截断 UNDO LOG 条目的功能,这些条目填充了 ibdata1 的 95%,并且在完全删除和恢复之后,从那一刻起,我的 ibdata1再也没有长大。

使用默认的 innodb_undo_log_truncate = 0 我的 ibdata1 轻松达到 10% 的数据库空间占用,也就是几十 GB。

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