MySQL之InnoDB存储结构
MySQL之InnoDB存储结构
本文转载于MySQL - InnoDB - 听雨危楼 - 博客园 (cnblogs.com)
InnoDB逻辑存储结构
表空间(table space)
在InnoDB存储引擎中,所有数据都存放在表空间(table space)中,表空间由段(segment)、区(extent)、页(page)、行(Row)组成,它们的关系如下图:
段(segment)
表空间由各个段组成,常见的段类型有:数据段、索引段、回滚段。
由于InnoDB表采用的是聚簇索引,所以数据段可以看成是B+树的叶子节点,索引段可以看成是B+树的非索引节点。
区(extend)
一个段由多个区组成,区由多个连续页组成,每个区的大小为1MB,默认情况下,每个页的大小为16KB:
1 | mysql> select @@innodb_page_size; |
即一个区中一共有64个连续页。用户可通过innodb_page_size参数设置每个页的大小。
默认情况下,用户在创建一张InnoDB表后,该表对应的独立表空间文件为96KB,在每个段开始时会先用32个碎片页来存放数据,使用完这32个页后才是64个连续页的申请。这么做是考虑到有些表的数据相对来说是比较少的,可以节省磁盘空间,因为申请64个页(即1个区)需要1MB空间。
页(page)
页是InnoDB磁盘管理的最小单位,默认大小为16KB。常见的页类型有:
- 数据页(B-tree Node)
- undo页(undo Log Page)
- 系统页(System Page)
- 事务数据页(Transaction system Page)
- 插入缓冲位图页(Insert Buffer Bitmap)
- 插入缓冲空闲列表页(Insert Buffer Free List)
- 未压缩的二进制大对象页(Uncompressed BLOB Page)
- 压缩的二进制大对象页(compressed BLOB Page)
行(Row)
InnoDB存储引擎将数据按行进行存放,每个页最多存放7992行记录(16KB除以2~200),InnoDB存储引擎提供了Compact、Redundant、Compressed、Dynamic四种格式来存放行记录数据,用户可通过命令show table status like 'table_name'来查看该属性。
其中Row_format就是行记录格式。
InnoDB物理存储结构
最直观的物理存储结构,我们能看到的,就是MySQL的存储目录data:
1 | [root@cs ~]# ll /data/mysql |
其中:
ib_logfile0 ~ ib_logfile1:REDO日志文件,事务日志文件ibdata1:系统数据字典(统计信息),UNDO表空间等数据ibtmp1:临时表空间磁盘位置,存储临时表
基于InnoDB的表都会建立:
frm:存储表的字段信息ibd:表的数据行和索引
表空间
https://dev.mysql.com/doc/refman/5.7/en/innodb-tablespace.html
MySQL在5.5版本(能够上生产环境,稳定的版本)才有了表空间(Table space)的概念,恰好这个时间节点是在被Oracle收购后…..
这里简单说说表空间。虽然MySQL将数据存储到段、区、页中,但是这其中还经历了一个逻辑层 ,物理层面的逻辑层!这里称之为表空间。
PS:一般提到表空间的概念,基本上都是说的是Oracle表空间,这里MySQL可能借鉴了……你有兴趣也可以参考LVM的原理,都类似。
如上图左侧部分,如果MySQL将ibd文件直接从内存中写入到sdb1磁盘中,如果有一天该sdb1磁盘满了怎么办?一般来说可以将sdb1中的数据导入到磁盘空间更大的磁盘sdb2中,然后MySQL后续直接往sdb2中写入数据即可,直到有一天………
MySQL为了解决这个问题,也可能是借鉴了Oracle…….在MySQL层和磁盘层中间再加上一层逻辑层,即表空间,MySQL将ibd文件都存储到table space层,后续的磁盘都可以动态的挂载到table space层……….
而在MySQL中的表空间,经过发展现在有共享表空间和独立表空间两个概念。
共享表空间
Innodb所有数据保存在一个单独的表空间里面,我们称这个表空间为共享表空间,毕竟所有表都在这个共享表空间里面嘛!
这个表空间可以由很多个文件组成,一个表可以跨多个文件存在,所以其大小限制不再是文件大小的限制,而是其自身的限制。从Innodb的官方文档中可以看到,其表空间的最大限制为64TB,也就是说,Innodb的单表限制基本上也在64TB左右了,当然这个大小是包括这个表的所有记录、索引和其他相关数据。
随着MySQL初始化时,默认的共享表空间也随之建立,即数据目录中的ibdata1文件(后续可以是多个),并且初始就一个ibdata1文件,且文件的初始大小为12MB,然后随着数据量的推移,以64MB为单位增加。
可以通过以下参数来查看该ibdata1文件:
1 | SELECT @@innodb_data_file_path; |
也可以vim /etc/my.cnf配置文件:
1 | # ---------- 在默认的datadir目录下设置多个 ibdata 文件 ---------- |
还有另一种情况就是:当没有配置innodb_data_file_path时,默认innodb_data_file_path = ibdata1:12M:autoextend;当需要改为1G时,不能直接在配置文件把 ibdata1 改为 1G ;而应该再添加一个 ibdata2:1G,如innodb_data_file_path = ibdata1:12M;ibdata2:1G:autoextend。
另外,一般,对于共享表空间的设置,在MySQL初始化之前就设计好了,那么在MySQL初始化的时候,按照你的设置,就自动的建立好相应的文件了。
MySQL5.6版本,共享空间虽然得以保留,但也只用来存储:数据字典、UNDO、临时表
而在5.7版本,临时表被独立出去了….
8.0版本,UNDO也被独立出去了…..
点击以下链接查看架构演示:
独立表空间
从5.6开始,默认表空间不再使用共享表空间,替换为独立表空间,主要存储的是用户数据。
存储特点:每个表都有自己的表空间,表空间内存放着ibd文件,idb文件被称之为表空间的数据文件,主要用来存储数据行以及索引信息;而基本的表结构和元数据存储在frm文件中。
除了上述的frm和ibd文件之外,还搭配的有:
Redo Log,重做日志。Undo Log,存储在共享表空间中,回滚日志。ibtmp,临时表,存储在JOIN和UNION操作产生的临时数据,用完自动删除。
独立表空间/共享表空间切换
我们可以对表的元数据、数据、索引信息进行单独管理,那么也能单独对表空间进行管理,比如设置表使用共享表空间。
通过innodb_file_per_table参数来控制MySQL对表使用共享表空间还是独立表空间,而默认值1表示使用独立表空间(一个表就是一个独立的idb文件),而改成0就是使用共享表空间。
1 | mysql> select @@innodb_file_per_table; |
现在我们测试一下,将innodb_file_per_table的值改为0,然后新建一张表(修改操作对原来建立的表没有影响,只会影响修改值后新建的表):
1 | mysql> set global innodb_file_per_table=0; |
现在,我们来看磁盘上的关于tt数据库下t6表的物理存储结构:
1 | [root@cs ~]# ll /data/mysql/tt/t6* |
上述结果中,t5表是之前建立的表,它有ibd和frm两个文件分别存储数据、索引和元数据信息;而innodb_file_per_table=0后创建的t6表,它的物理存储结构中,就只剩下了frm文件,用来存储元数据信息,而数据和索引信息不在存储自己的独立表空间中,即自己的idb文件中了,而是存储到了共享表空间中了(idbata)。

