为什么 InnoDB 将所有数据库存储在一个文件中?

Goo*_*bot 56 mysql innodb myisam mysqldump mysql-5.5

MyISAM 用于将每个表存储在相应的文件中很方便。InnoDB 在很多方面都取得了进步,但我想知道为什么 InnoDB 将所有数据库存储在一个文件中(ibdata1默认情况下)。

我知道 InnoDB 将通过表的单个索引文件映射文件中数据的位置,但我不明白为什么它将所有数据混合在一个文件中。更重要的是,为什么要混合服务器上所有数据库的数据?

MyISAM 的一个有趣功能是,可以将数据库文件夹复制/粘贴到另一台机器上,然后使用该数据库(无需转储)。

Rol*_*DBA 70

InnoDB 的架构需要使用四种基本类型的信息页面

  • 表数据页
  • 表索引页
  • 表元数据
  • MVCC数据(支持事务隔离和ACID 合规性
    • 回滚段
    • 撤消空间
    • 双写入缓冲区(后台写入以防止依赖操作系统缓存)
    • 插入缓冲区(管理对非唯一二级索引的更改)

参见ibdata1的图示

默认情况下,innodb_file_per_table被禁用。这会导致所有四种信息页面类型都放置一个名为 ibdata1 的文件。许多人试图通过制作多个 ibdata 文件来分散数据。这可能会导致数据和索引页的碎片化。

这就是为什么我经常建议清理 InnoDB 基础设施,使用默认的 ibdata1 文件,仅此而已

由于 InnoDB 工作的基础架构,复制非常危险。有两个基本的基础设施

  • innodb_file_per_table 已禁用
  • 启用 innodb_file_per_table

InnoDB(禁用innodb_file_per_table

随着innodb_file_per_table禁用,所有这些类型的InnoDB的信息ibdata1中内直播。ibdata1 之外的任何 InnoDB 表的唯一表现形式是 InnoDB 表的 .frm 文件。一次复制所有 InnoDB 数据需要复制所有 /var/lib/mysql。

复制单个 InnoDB 表是完全不可能的。您必须 MySQL 转储以提取表的转储作为数据及其相应索引定义的逻辑表示。然后,您将该转储加载到同一服务器或另一台服务器上的另一个数据库。

InnoDB(启用innodb_file_per_table

随着innodb_file_per_table启用,表中的数据及其索引住在数据库文件夹旁边的.frm文件。例如,对于表 db1.mytable,该 InnoDB 表在 ibdata1 之外的表现形式为:

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

系统表空间 ibdata1

db1.mytable 的所有元数据仍然驻留在 ibdata1 中,绝对没有办法解决这个问题。重做日志和 MVCC 数据也仍然存在于 ibdata1 中。

当涉及到表碎片时,ibdata1 会发生以下情况:

  • innodb_file_per_table 已启用:您可以使用ALTER TABLE db1.mytable ENGINE=InnoDB;或缩小 db1.mytablesOPTIMIZE TABLE db1.mytable;。这导致 /var/lib/mysql/db1/mytable.ibd 在物理上更小,没有碎片。
  • innodb_file_per_table disabled:你不能收缩 db1.mytablesALTER TABLE db1.mytable ENGINE=InnoDB;OPTIMIZE TABLE db1.mytable;因为它驻留在 ibdata1。实际上运行任一命令,使表连续且读取和写入速度更快。不幸的是,这发生在 ibdata1 的末尾。这使得 ibdata1 增长迅速。这在我的 InnoDB Cleanup Post 中得到了充分的解决

警告(或机器人在《迷失太空》中所说的危险)

如果您只想复制 .frm 和 .ibd 文件,那么您就是在受伤害的世界。复制 InnoDB 表的 .frm 和 .ibd 文件仅当且仅当您可以保证 .ibd 文件的表空间 id 与 ibdata1 文件的元数据中的表空间 id 条目完全匹配时才有效

我在 DBA StackExchange 中写了两篇关于这个表空间 ID 概念的文章

这是一个关于如何在表空间 ID 不匹配的情况下将任何 .ibd 文件重新附加到 ibdata1 的极好链接:http : //www.chriscalender.com/ ? tag=innodb-error-tablespace-id-in-file 。阅读本文后,您应该立即意识到复制 .ibd 文件简直是疯了。

对于 InnoDB,你只需要移动这个东西

CREATE TABLE db2.mytable LIKE db1.mytable;
INSERT INTO db2.mytable SELECT * FROM db1.mytable;
Run Code Online (Sandbox Code Playgroud)

制作 InnoDB 表的副本。

如果要将其迁移到另一个数据库服务器,请使用 mysqldump。

关于混合来自所有数据库的所有 InnoDB 表,我实际上可以看到这样做的智慧。在我雇主的 DB/Web 托管公司,我有一个 MySQL 客户端,它在一个数据库中有一个表,其约束映射到同一 MySQL 实例中另一个数据库中的另一个表。通过一个通用的元数据存储库,它使跨多个数据库的事务支持和 MVCC 可操作性成为可能。


atx*_*dba 14

您可以通过将 innodb-file-per-table 添加到您的 cnf 来切换 InnoDB 以存储每个文件的表。

Innodb 实际上只关心基本级别的数据页。事实上,您可以将 InnoDB 设置为仅使用原始块设备,而无需任何文件系统!http://dev.mysql.com/doc/refman/5.5/en/innodb-raw-devices.html

为文件存储表有很多便利,例如能够通过优化更轻松地重新获得已用空间。

即使每个表都有文件,您也不能简单地复制 ibd 文件,因为 InnoDB 是事务性的,并且将有关其状态的信息存储在全局共享的 ibdata/log 文件中。

这并不是说它不能完成。如果表离线,您可以丢弃/导入表空间并复制http://dev.mysql.com/doc/refman/5.5/en/innodb-multiple-tablespaces.html周围的 .idbs


ype*_*eᵀᴹ 10

这是默认行为,但不是强制性的。来自MySQL 文档,使用每表表空间

默认情况下,所有 InnoDB 表和索引都存储在系统表空间中。作为替代方案,您可以将每个 InnoDB 表及其索引存储在自己的文件中。此功能称为“多个表空间”,因为此设置生效时创建的每个表都有自己的表空间。

至于为什么,原因可能是两个引擎(MyISAM和InnoDB)的架构不同。例如,在 InnoDB 中,您不能只是将 .ibd 文件复制到另一个数据库或安装。说明(来自同一页面):

.ibd 文件的可移植性注意事项

您不能像使用 MyISAM 表文件那样在数据库目录之间自由移动 .ibd 文件。存储在 InnoDB 共享表空间中的表定义包括数据库名称。存储在表空间文件中的事务 ID 和日志序列号也因数据库而异。