【问题标题】:Howto: Clean a mysql InnoDB storage engine?如何:清理 mysql InnoDB 存储引擎?
【发布时间】:2011-04-25 01:40:27
【问题描述】:

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

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

【问题讨论】:

  • 是什么让您认为 MySQL 正在存储已删除表中的数据?
  • 如果我删除一大堆大表,我的 InnoDB 存储文件不会缩小
  • @RobertMunteanu:见bugs.mysql.com/bug.php?id=1341

标签: mysql innodb


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

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

    InnoDB 架构

    许多人创建多个 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,仍保留在数据字典中(请参阅Pictorial Representation of ibdata1)。 此时您不能简单地删除 ibdata1 !!! 请注意,ibdata1 根本没有缩小。

    InnoDB 基础架构清理

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

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

    2. 删除所有数据库(mysqlinformation_schema 除外)CAVEAT:作为预防措施,请运行此脚本以确保您已获得所有用户授权:

      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(或 Windows 上的 my.ini

      [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中的所有文件夹,/var/lib/mysql/mysql除外。

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

    8. 导入SQLData.sql

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

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

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

    使用/etc/my.cnf 中的innodb_file_per_table 选项,您可以运行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 有一篇很好的文章why to choose a proper innodb_log_file_size。后来,在Nov 21, 2008,Percona 又在how to calculate the proper size based on peak workload keeping one hour's worth of changes 上跟进了另一篇文章。

    我已经在 DBA StackExchange 上写过关于计算日志大小以及我在哪里引用了那两篇 Percona 文章的帖子。

    就个人而言,我仍然会使用 25% 的规则进行初始设置。然后,随着生产时间的推移,可以更准确地确定工作负载,you could resize the logs 在维护周期内只需几分钟。

    【讨论】:

    • 我还使用了 innodb_file_per_table 选项,效果很好,在一个服务器上有 200 个数据库,每个数据库有 200 个表,我能够将不同的数据库符号链接到不同的分区,因此使用更多的 IO 缓冲区和主轴本来可以使用的:)
    • @SeanDowney BTW 记得在必要时提出innodb_open_tables。默认值为 300。
    • @giorgio79 您需要将批量插入设置为更大的值。这是个好的观点。我会将您问题的本质添加到我的答案中。
    • 在 32 位系统中,innodb_buffer_pool_size 的 4Gb 值是不允许的。 Mysql 将在禁用 innodb 的情况下静默启动,并且恢复的表将更改为 myisam。使用稍小的值来修复它。
    • 天哪。我只想说这可能是我在 S.O. 上见过的最好的答案之一。干得好,先生。当我在导入 154g 数据库时遇到 ERROR 2013 (HY000) 时,帮助我找到了解决问题的方法。感谢您的出色回答!
    【解决方案3】:

    我按照本指南进行完全重置(以 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
    

    【讨论】:

      猜你喜欢
      • 2016-12-23
      • 1970-01-01
      • 2019-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-25
      • 2012-05-04
      相关资源
      最近更新 更多