如何:清理一个MySQL InnoDB存储引擎?


133

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

还是我每次都必须重建一个新的数据库?


是什么让您认为MySQL正在存储已删除表中的数据?
罗伯特·蒙提亚努

1
如果我丢掉一大堆大表,我的InnoDB存储文件将不会缩小
Bryan Field 2010年

2
@RobertMunteanu:看bugs.mysql.com/bug.php?id=1341
马克斯

Answers:


351

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

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

InnoDB架构

InnoDB架构

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

我可以跑步OPTIMIZE TABLE吗?

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

  • 使表的数据和索引在内部连续 ibdata1
  • 使得ibdata1成长,因为连续的数据和索引页被追加ibdata1

但是,您可以从中分离表数据和表索引ibdata1并分别进行管理。

我可以运行OPTIMIZE TABLE使用innodb_file_per_table

假设您要添加innodb_file_per_table/etc/my.cnf (my.ini)。然后可以只OPTIMIZE TABLE在所有InnoDB表上运行吗?

好消息:启用后运行OPTIMIZE TABLEinnodb_file_per_table,将.ibd为该表生成一个文件。例如,如果您的表的mydb.mytabledatadir为/var/lib/mysql,它将产生以下结果:

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

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

坏消息:您所要做的就是mydb.mytable从生活中提取的数据页和索引页ibdata。每个表(包括)的数据字典条目mydb.mytable仍保留在数据字典中(请参阅ibdata1图形表示)。您不能在ibdata1这一点上简单地删除!!!请注意,ibdata1它根本没有缩小。

InnoDB基础架构清理

ibdata1一劳永逸地缩小,您必须执行以下操作:

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

  2. 删除所有数据库(mysql和除外information_schemaCAVEAT:为慎重起见,请运行此脚本以确保您已拥有所有用户授权:

    mkdir /var/lib/mysql_grants
    cp /var/lib/mysql/mysql/* /var/lib/mysql_grants/.
    chown -R mysql:mysql /var/lib/mysql_grants
    
  3. 登录到MySQL并运行SET GLOBAL innodb_fast_shutdown = 0;(这将彻底从刷新所有剩余事务变化ib_logfile0ib_logfile1

  4. 关闭MySQL

  5. 将以下行添加到/etc/my.cnf(或my.ini在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_size为的25%innodb_buffer_pool_size

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

  6. 删除,ibdata*并且ib_logfile*可以选择删除中的所有文件夹/var/lib/mysql,除了/var/lib/mysql/mysql

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

  8. 进口 SQLData.sql

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

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

  • mytable.frm (存储引擎标题)
  • mytable.ibd (表数据和索引)

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

在我作为MySQL DBA的职业生涯中,我做了很多次。实际上,我第一次这样做是将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 EDT

关于在步骤5 中将innodb_log_file_size设置为innodb_buffer_pool_size的 25%,这是总括规则,这是相当老套的规则。

回顾一下July 03, 2006,Percona有一篇不错的文章,为什么要选择适当的innodb_log_file_size。后来,Nov 21, 2008Percona继续撰写另一篇文章,介绍如何根据峰值工作量计算适当的大小,并保持一小时的更改价值

此后,我在DBA StackExchange中撰写了有关计算日志大小以及在其中引用这两篇Percona文章的文章。

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


9
我还使用了innodb_file_per_table选项,在单个服务器上有200个数据库(每个数据库有200个表),因此效果很好,我能够将差异数据库符号链接到不同的分区上,因此可以使用更多的IO缓冲区和主轴。
Dave Rix

2
@SeanDowney BTW记得innodb_open_tables在必要时加注。默认值是300
RolandoMySQLDBA

2
@ giorgio79,您需要将批量插入设置为更大的值。这是个好的观点。我会将您问题的实质添加到我的答案中。
RolandoMySQLDBA 2012年

3
在32位系统中,innodb_buffer_pool_size的4Gb值是不允许的。Mysql将在禁用innodb的情况下以静默方式启动,还原的表将更改为myisam。使用稍小的值进行修复。
大卫

5
天哪 我只想说这可能是我见过的最好的答案之一,先生,很好。当我导入154g数据库时遇到错误2013(HY000)时,帮助我找出了解决问题的方法。感谢您的出色回答!
乔什·布朗

4

InnoDB引擎不存储已删除的数据。当您插入和删除行时,InnoDB存储文件中会保留未使用的空间。随着时间的流逝,总体空间不会减少,但是随着时间的流逝,“已删除和释放”的空间将由数据库服务器自动重用。

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

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.