如何: 清理 mysql InnoDB 存储引擎?

是否有可能清理 mysql indodb 存储引擎,使其不存储已删除表中的数据?

还是每次都要重建一个新的数据库?

172680 次浏览

InnoDB 引擎不存储已删除的数据。在插入和删除行时,将在 InnoDB 存储文件中分配未使用的空间。随着时间的推移,总体空间不会减少,但随着时间的推移,“删除和释放”的空间将被 DB 服务器自动重用。

您可以通过手动重新组织表来进一步优化和管理引擎使用的空间。为此,可以使用 mysqldump 在受影响的表中转储数据,删除表,重新启动 mysql 服务,然后从转储文件重新创建表。

下面是关于 InnoDB 的一个更完整的答案。这是一个有点漫长的过程,但值得付出努力。

请记住,/var/lib/mysql/ibdata1是 InnoDB 基础设施中最繁忙的文件,它通常包含六种类型的信息:

InnoDB 架构

InnoDB Architecture

许多人创建多个 ibdata文件,希望获得更好的磁盘空间管理和性能,然而这种想法是错误的。

我能运行 强 > OPTIMIZE TABLE吗?

不幸的是,对共享表空间文件 ibdata1中存储的 InnoDB 表运行 强 > OPTIMIZE TABLE会做两件事:

  • 使表的数据和索引在 ibdata1内连续
  • 使 ibdata1增长,因为连续的数据和索引页是 附件ibdata1

但是,可以将表数据和表索引与 ibdata1分离并独立管理它们。

我能用 innodb_file_per_table 运行 强 > OPTIMIZE TABLE吗?

假设您要将 强 > innodb_file_per_table添加到 /etc/my.cnf (my.ini),那么您可以在所有的 InnoDB 表上运行 OPTIMIZE TABLE 吗?

好消息 : 启用 innodb_file_per_table 运行 强 > OPTIMIZE TABLE时,将为该表生成一个 .ibd文件。例如,如果表 mydb.mytable的数据目录为 /var/lib/mysql,那么它将产生以下结果:

  • /var/lib/mysql/mydb/mytable.frm
  • /var/lib/mysql/mydb/mytable.ibd

.ibd将包含该表的数据页和索引页。

坏消息 : 你所做的就是从 ibdata中提取出 mydb.mytable的数据页和索引页。每个表的数据段落,包括 mydb.mytable,仍然保留在数据字典中(见 Ibdata1的图形化表示)。请注意,ibdata1根本没有缩水。

基础设施清理

要一劳永逸地缩小 ibdata1,你必须做到以下几点:

  1. 将所有数据库转储(例如,使用 mysqldump)到一个 .sql文本文件中(下面使用 SQLData.sql)

  2. 删除所有数据库(除了 mysqlinformation_schema) 警告: 作为预防措施,请运行这个脚本,以确保所有用户授权都到位:

    mkdir /var/lib/mysql_grants
    cp /var/lib/mysql/mysql/* /var/lib/mysql_grants/.
    chown -R mysql:mysql /var/lib/mysql_grants
    
  3. Login to mysql and run SET GLOBAL innodb_fast_shutdown = 0; (This will completely flush all remaining transactional changes from ib_logfile0 and ib_logfile1)

  4. Shutdown MySQL

  5. Add the following lines to /etc/my.cnf (or my.ini on Windows)

    [mysqld]
    innodb_file_per_table
    innodb_flush_method=O_DIRECT
    innodb_log_file_size=1G
    innodb_buffer_pool_size=4G
    

    (旁注: 不管你的 innodb_buffer_pool_size设置是什么,确保 innodb_log_file_sizeinnodb_buffer_pool_size的25% 。

    另外: innodb_flush_method=O_DIRECT在 Windows 上不可用)

  6. 删除 ibdata*ib_logfile*,也可以删除除 /var/lib/mysql/mysql以外的 /var/lib/mysql中的所有文件夹。

  7. 启动 MySQL (这将在1G 时重新创建 ibdata1[默认为10MB ]和 ib_logfile0ib_logfile1)。

  8. 进口 SQLData.sql

现在,ibdata1仍将增长,但只包含表元数据,因为每个 InnoDB 表都将存在于 ibdata1之外。ibdata1将不再包含 InnoDB 数据和其他表的索引。

例如,假设您有一个名为 mydb.mytable的 InnoDB 表。如果查看 /var/lib/mysql/mydb,您将看到表示该表的两个文件:

  • mytable.frm(存储引擎头)
  • 表格数据和索引

使用 /etc/my.cnf中的 innodb_file_per_table选项,您可以运行 OPTIMIZE TABLE mydb.mytable,而文件 /var/lib/mysql/mydb/mytable.ibd实际上将收缩。

在我作为 MySQL 数据库管理员的职业生涯中,我已经这样做过很多次了。事实上,我第一次这样做时,我将 50GB ibdata1文件缩小到只有500MB!

试试看。如果你还有什么问题,尽管问。相信我,这在短期和长期都是有效的。

警告

在步骤6中,如果由于 mysql模式开始被删除,mysql 无法重新启动,请回头看步骤2。您创建了 mysql模式的物理副本。你可以恢复如下:

mkdir /var/lib/mysql/mysql
cp /var/lib/mysql_grants/* /var/lib/mysql/mysql
chown -R mysql:mysql /var/lib/mysql/mysql

回到第6步,继续

更新2013-06-04美国东部时间11:13

关于在步骤5中将 Nodb _ log _ file _ size设置为 Inodb _ buffer _ pool _ size的25% ,这是一个相当古老的规则。

回到 July 03, 2006,Percona 写了一篇不错的文章 为什么要选择适当的 inodb _ log _ file _ size。之后,在 Nov 21, 2008,Percona 又写了一篇关于 如何计算适当的大小基于高峰工作负载保持一个小时的变化价值的文章。

此后,我在 DBA StackExchange 上撰写了关于计算日志大小的文章,并在其中引用了那两篇 Percona 文章。

就个人而言,我仍然会采用初始设置的25% 规则。然后,随着生产时间的推移,可以更准确地确定工作负载,您可以调整日志的大小在一个维护周期内只需几分钟。

我遵循以下指南来完全重置(作为 root 用户) :

mysqldump --all-databases --single-transaction | gzip -c > /tmp/mysql.all.sql.gz
service mysql stop
mv /var/lib/mysql /var/lib/mysql.old; mkdir -m700 /var/lib/mysql; chown mysql:mysql /var/lib/mysql


mysql_install_db                # mysql 5.5
mysqld --initialize-insecure    # mysql 5.7


service mysql start
zcat /tmp/mysql.all.sql.gz | mysql
service mysql restart

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

看看我在 如何在 MySQL 中收缩/清除 ibdata1文件上的答案。