InnoDB引擎逻辑存储结构

(本片博文是《MySQL技术内幕 InnoDB存储引擎第二版》的读书笔记)

索引组织表

InnoDB存储引擎中,表都是按照主键顺序组织存放的,这种存储方式的表称为索引组织表(index organized table)。InnoDB存储引擎表中,每张表都有个主键,若在创建表时没有显式定义主键则InnoDB存储引擎会按如下方式选择或者创建主键:

  • 首先判断表中是否有非空的唯一索引(Unique NOT NULL),如果有,则该列即为主键。(当表中有多个非空唯一索引时,InnoDB存储引擎将选择建表时第一个定义的非空唯一索引为主键,注意是根据定义索引的顺序而不是建表时列的顺序)。
  • 如果不符上述条件,则会自动创建一个6字节大小的指针。

InnoDB逻辑存储结构

这是《MySQL技术内幕 InnoDB存储引擎》一书中对InnoDB逻辑存储结构的描述。


InnoDB引擎逻辑存储结构_第1张图片
1.PNG

表空间

表空间是Innodb存储引擎逻辑的最高层,所有的数据都存放在表空间中,默认情况下,Innodb存储引擎有一个共享表空间ibdata1,即所有数据都存放在这个表空间中内。如果启用了innodb_file_per_table参数,则每张表内的数据可以单独放到一个表空间内,但请注意,只有数据、索引、和插入缓冲Bitmap放入单独表内,其他数据,比如回滚(undo)信息、插入缓冲检索页、系统事物信息,二次写缓冲等还是放在原来的共享表内的。

从上图中可以看出表空间由段组成,常见的段有数据段、索引段、回滚段等。因为InnoDB存储引擎表是索引组织的,因此数据即索引,索引即数据。数据段即为B+树的叶子结点,索引段即为B+树的非索引结点。在InnoDB存储引擎中对段的管理都是由引擎自身所完成,DBA不能也没必要对其进行控制。

区是由连续页组成的空间,在任何情况下每个区的大小都为1MB。为了保证区中页的连续性,InnoDB存储引擎一次从磁盘申请4~5个区。默认情况下,InnoDB存储引擎页的大小为16KB,一个区中一共64个连续的区。

页(块)

页是InnoDB磁盘管理的最小单位。在InnoDB存储引擎中,默认每个页的大小为16KB。从InnoDB1.2.x版本开始,可以通过参数innodb_page_size将页的大小设置为4K,8K,16K。若设置完成,则所有表中页的大小都固定,不可以对其再次修改。除非通过mysqldump导入和导出操作来产生新的库。
InnoDB存储引擎中,常见的页类型有:数据页,undo页,系统页,事务数据页,插入缓冲位图页,插入缓冲空闲列表页等。

InnoDB数据页结构

InnoDB数据页结构如下图:

InnoDB引擎逻辑存储结构_第2张图片
1.PNG

其中File Header、Page Header、File Trailer的大小是固定的,分别为38,56,8字节,这些空间用来标记该页的一些信息,如Checksum,数据页所在B+树索引的层数等。User Records、Free Space、Page Directory这些部分为实际的行记录存储空间,因此大小是动态的。

1.File Header用来记录页的一些头信息,由表中8个部分组成,共占38字节。各部分代表信息如下表所示:

InnoDB引擎逻辑存储结构_第3张图片
1.PNG

InnoDB引擎逻辑存储结构_第4张图片
2.PNG

2.Page Header用来记录数据页的状态信息,14个部分组成,共占56字节。各部分代表信息如下表所示:

InnoDB引擎逻辑存储结构_第5张图片
1.PNG

InnoDB引擎逻辑存储结构_第6张图片
2.PNG

3.Infimum和Supermum Record是InnoDB中两个虚拟的行记录,用来限定记录的边界。Infimum记录是比该页中任何主键值都要小的值,Supermum是比任何可能大的值还要大的值。这两个记录在页创建时被建立,并且在任何情况下都不会被删除。下图显示了Infimum记录和Supermum记录:
InnoDB引擎逻辑存储结构_第7张图片
3.PNG

4.User Record和Free Space

User Record就是实际存储行记录的内容。InnoDB存储引擎表总是B+树索引组织的。Free Space指空闲空间,是链表数据结构,在一条记录被删除后,该空间会被加入到空闲链表中。
5.Page Directory

Page Directory中存放了记录的相对位置(是页相对位置而不是偏移量),有时这些记录指针称为Slots(槽)或者目录槽(Directory Slots)。与其他数据库系统不同的是,在InnoDB中并不是每个记录拥有一个槽,InnoDB存储引擎的槽是一个稀疏目录(sparse directory),即一个槽中可能包含多个纪录。伪记录的Infimum的n_owned值总是为1,记录Supermum的n_owned的取值范围为[1,8],其他用户记录n_owned的取值范围为[4,8]。当记录被插入或删除时需要对槽进行分裂或平衡的维护操作。

在Slots中记录按照索引键值顺序存放,这样可以利用二叉查找迅速找到记录的指针。假设有('i','d','c','b','e','g','l','h','f','j','k','a'),同时假设一个槽中包含4条记录,则Slots中的记录可能是('a','e','i')。

由于在InnoDB存储引擎中Page Directory是稀疏目录,二叉查找的结果只是一个粗略结果,因此InnoDB存储引擎必须通过recorder header中的next_record来继续查找相关记录。同时,Page Directory很好地解释了recorder header中的n_owned值的含义,因为这些记录并不包括在Page Directory中。

B+树索引本身并不能找到具体的一条记录,能找到只是改记录所在的页。数据库把页载入到内存,然后通过Page Directory再进行二叉查找。只不过二叉查找的时间复杂度很低,同时在内存中的查找很快,因此通常忽略这部分查找所用的时间。

6.File Trailer
该部分是为了检测页是否已经完整地写入磁盘的(可能在写入过程中磁盘损坏、机器关机等)。该部分占用8字节,前4字节代表该页的checksum值,后4字节和File Header中的FIL_PAGE_LSN相同。将这两个值与File Header中的FIL_PAGE_SPACE_OR_CHKSUM和FIL_PAGE_LSN值进行比较,看是否一致(checksum的比较需要通过InnoDB的checksum函数来比较,不是简单的等值比较),以此来保证页的完整新。

InnoDB存储引擎是面向列的,也就是说数据按行存放。每个页存放的行记录也是有硬性定义的,最多允许存放16KB/2-200=7992行记录。
InnoDB存储引擎提供了Compact和Redundant两种格式来存放行记录数据,Redundant格式是为兼容之前版本而保留的。5.1版本中,默认设置为Compact行格式。可以通过命令SHOW TABLE STATUS LIKE 'table_name'来查看当前表使用的行格式,其中row_format属性表示行记录类型。

Compact行记录格式

3.PNG

上图就是Compact行记录的存储方式。由图可知, 首部是一个非NULL变长字段长度列表,并且是按照列的顺序逆序放置的,长度为:

  • 若列的长度小于255字节,用1字节表示;
  • 若大于255字节,用2字节表示。

变长字段的长度最大不可以超过2字节,因为在MySQL中VARCHAR类型的最大长度限制为65535。变长字段之后的第二个部分是NULL标志位,指示了该行数据中是否有NULL值,有则用1表示,占1字节。接下来是记录头信息,固定占用5字节。每位的含义见下表

InnoDB引擎逻辑存储结构_第8张图片
4.PNG

最后的部分就是 实际存储每个列的数据。NULL不占该部分任何空间,即NULL除了占有NULL标志位,实际存储不占有任何空间。另外有一点需要注意的是,每行数据除了用户定义的列外,还有两个隐藏列,事务ID和回滚指针列,分别为6字节和7字节的大小。若InnoDB表没有定义主键,每行还会增加一个6字节的rowid列。

Redundant行记录格式

Redundant是MySQL5.0版本之前InnoDB的行记录存储方式,MySQL5.0支持Redundant是为了兼容之前版本的页格式。Redundant行记录采用如图所示的方式存储。

1.PNG

首部是字段长度偏移列表,按照列的顺序逆序放置。若列的长度小于255字节,用1字节表示;若大于255字节,用2字节表示。第二部分为 记录头信息,占用6字节,每位含义如下表
InnoDB引擎逻辑存储结构_第9张图片
2.PNG

从表中可以看出,n_fields值代表一行中列的数量,占用10位,很好的解释了为什么MySQL数据库一行支持最多的列为1023。另一个需要知道的是1byte_offs_flags,该值定义了偏移列表占用1字节还是2字节。最后的部分就是实际存储的每个列的数据了。

你可能感兴趣的:(InnoDB引擎逻辑存储结构)