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


51

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

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

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

Answers:


66

InnoDB的体系结构要求使用四种基本类型的信息页面

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

请参阅ibdata1的图形表示

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

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

由于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:您不能使用ALTER TABLE db1.mytable ENGINE=InnoDB;或收缩db1.mytables,OPTIMIZE TABLE db1.mytable;因为它驻留在ibdata1中。实际上运行这两个命令,可使表连续且读写更快。不幸的是,这发生在ibdata1的末尾。这使ibdata1快速增长。我的InnoDB清理帖子中已完全解决了这一问题

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

如果您只想复制.frm和.ibd文件,那么您就很容易受到伤害。仅当且仅当您可以确保.ibd文件的表空间ID与ibdata1文件的元数据中的表空间ID项完全匹配时,才可以复制InnoDB表的.frm和.ibd 文件

我在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;

制作一个InnoDB表的副本。

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

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


这是否意味着当我为每个表启用innodb文件时,并且如果我需要将数据从一台服务器导入到另一台服务器,则仅需使用mysqldump而不使用任何其他工具(如Percona xtrabackup)?
tesla747 '16

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。


毫无疑问,InnoDB是一种灵活的引擎,但是我不明白将所有数据存储在一个文件中有何好处(因为与MyISAM相比,这种新结构已在InnoDB中实现了)。
Googlebot 2012年

我认为,事后诸葛亮之一是20/20。在innodb首次推出后,就添加了“每表文件”选项。除了提供它自己的块设备来避免文件系统开销外,我无法提供将它们全部一起转储更好的原因(整个块设备的问题是它自己的争论)。我所有的innodb设置都启用了每个表的文件。
atxdba 2012年

重点在于,不依赖文件系统可能是无价之宝,但默认情况下它不处于活动状态。因此,一些用户将使用它。
Googlebot 2012年

1
如果您有很多表而没有太多RAM,则每个表一个文件选项可能会造成危害(例如,Magento商店可能有约1000个表)。并且打开文件的设置也必须进行优化(考虑到操作系统的限制)。因此,请谨慎使用。
ypercubeᵀᴹ

当然,它可以阻碍恢复工作。是的,您应该有一个备份,但是如果没有,InnoDB会因为这种结构而使事情变得更难。
mikato 2015年

10

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

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

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

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

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


很有信息的答案并澄清了问题,但我仍然很好奇包含所有数据库的大文件如何提高性能(如果可以)。
Googlebot 2012年

由于所有文件都只有一个,因此性能并不是更好。各种特性(如行级锁定而不是表级锁定)有助于提高性能。当然,主要的优势是事务和FK约束(以及数据库的完整性)。
ypercubeᵀᴹ

1
您完全正确!我知道为什么最好将数据库的所有表放在一个singe文件中;但是我不明白为什么要将所有数据库(完全独立)放在同一个文件中。默认情况下,InnoDB仅使用一个文件来存储数据。
Googlebot 2012年
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.