作者:阿茂
上一篇我们聊了InnoDB内存结构,这一篇我们聊一聊数据在磁盘上的结构。纯聊理论确实比较枯燥,感觉也没啥营养,我在这里只是想方便大家对MySQL的整体结构有个详细的了解,在后面的文章中我会频繁的提到这些内容,先整体的过一遍有个印象。下面我就开始说InnoDb的数据磁盘结构(本篇文章不做特殊说明都是按照Mysq 5.7来讲解的)。表大家都不陌生吧,整天CRUD的数据都在这里,也是一个系统的业务价值所在,建议大家带着对数据的敬畏之心去写代码。在MySQL中每建一张表都会生成一个.frm文件,该文件是用来保存每个表的元数据信息的,主要包含表结构定义。在InnoDB给我们的表提供两种表空间存储方式,默认为共享表空间,存储的文件即为后缀ibdata1共享表空间,还有一种就是独占表空间:一张表单独一个表空间(.ibd),它的存储逻辑分为表空间(Tablespace)、段 (Segment)、区 (Extent)、页 (Page) 以及行 (row)。
行,页,区,段,表空间行:表的行格式决定了其行的物理存储方式,进而会影响查询和DML操作的性能。如果大量的行适合单个磁盘页,查询和索引查找可以更快地工作,缓冲池中需要的缓存内存更少,以及写出更新值所需的IO更少。每个表中的数据分为几页。构成每个表的页以称为B树索引的树数据结构排列。表数据和二级索引都使用这种类型的结构。表示整个表的B树索引称为聚簇索引,该聚簇索引是根据主键列进行组织的。聚集索引数据结构的节点包含该行中所有列的值。次要索引结构的节点包含索引列和主键列的值。(可变列例外,它长度超过上限后被分配在单独的磁盘页)
页:每个表空间由数据库页组成 。MySQL实例中的每个表空间都具有相同的页大小,默认页大小16K。可以使用innodb_page_size在创建MySQL实例的时候设置页大小。
区:默认一个区由64个连续的16KB页组成大小为1MB。
段:默认情况下InnoDB将一个区的前32页一次分配给它,随着段在数据库内增长时,会将整个区分配给这个段。一次最多向段中添加4个区,以保障数据的良好顺序。 一个索引分配两个段,分别存贮叶子节点和非叶子节点,这样可以保证叶子节点在磁盘上的连续性。
表空间系统表空间:系统表空间是InnoDB数据字典,双写缓冲区,Change Buffer和undo log的存储区 。属于一种共享表空间。
独占表空间:含单个InnoDB表的数据和索引 ,并存储在文件系统中自己的数据文件中。
常规表空间:类似于系统表空间,可以存储多个表的数据的一直共享表空间,支持Antelope和Barracuda文件格式。
undo表空间:undo表空间包含undo log撤销记录的集合,其中包含通过主键索引事务撤销更改的最小信息。
InnoDB数据字典
InnoDB数据字典包括包含用于跟踪对象,如表,索引,和表中的列的元数据的内部系统表。元数据实际上位于InnoDB系统表空间中。由于历史原因,数据字典元数据在某种程度上与InnoDB表元数据文件(.frm文件)中存储的信息重叠。
双写缓冲区
双写表空间位于系统表空间中的存储区域,InnoDB在Buffer Pool中刷新页面时,会将数据页写入doublewrite缓冲区后才会写入磁盘。当在写入OS Cache或者磁盘mysql进程奔溃后, InnoDB启动崩溃恢复能从doublewrite找到完整的副本用来恢复。尽管看起来数据被写了两次但是双写缓冲区并不需要双倍的IO的开销。 fsync() 只需对操作系统进行一次调用,就可以将数据作为一个较大的顺序块写入双写缓冲区本身。使用参数innodb_doublewrite=0关闭双写缓冲区,默认开启。
redo log
redo log是基于磁盘的数据结构,在崩溃恢复期间用于纠正不完整事务写入的数据。在初始化期间以及接受连接之前,会自动重放上次关闭之前未完成更新数据文件的修改。 MySQL以循环方式写入重做日志文件,默认会产生ib_logfile0 和 ib_logfile1两个文件,通过innodb_log_file_size增加redo log大小,innodb_log_files_in_group来增加日志数量。InnoDB在提交事务之前刷新事务的redo log,InnoDB使用组提交功能将多个此类刷新请求分组在一起批量提交,保障系统的吞吐性能。
undo log
undo log是与单个读写事务关联的撤消日志记录的集合。undo log记录包含有关如何撤消事务对聚簇索引记录的最新更改的信息。如果另一个事务需要将原始数据视为一致性读操作的一部分,则将从undo log记录中检索未修改的数据。undo log存在于undo log段中,回滚段位于系统表空间,undo表空间和临时表空间中。驻留在临时表空间中的undo log用于修改用户定义的临时表中的数据的事务。这些undo log没有redo log,因为崩溃恢复不需要它们。它们仅在服务器运行时用于回滚。innodb_rollback_segments可以定义回滚段的数量,最大支持128。
##结尾 这一篇我们就讲到这里,可能有细心的人会问了,binlog 那么重要为什么没讲呢?,那是应为binlog的是Mysql自身的设计,而不是InnoDB的架构引入的,可以去回顾下我们第一章的MySQL逻辑架构。纯讲理论确实比较枯燥,但是有些理论基础是想要深入不可逾越的一道坎。下期文章预告,我们开始说索引,尽量避免纯理论讲述,谢谢大家,要是文章对你有帮助请分享给别的小伙伴。
参考文章: