0%

mysql03_Innodb数据存储结构

索引组织表

在 InnoDB存储引擎中,表都是根据主键顺序组织存放的,这种存储方式的表称
索引组织表( index organized table)。

在 InnoDB存储引擎表中,每张表都有个主键( Primary Key),如果在创建表时没有显式地定义主键,则InnoDB存储引擎会按如下方式选择或创建主键:

  1. 首先判断表中是否有非空的唯一索引( Unique NOT NULI),如果有,则该列即为主键。
  2. 如果不符合上述条件, InnoDB存储引擎自动创建一个6字节大小的指针。

当表中有多个非空唯一索引时, InnoDB存储引擎将选择建表时第一个定义的非空唯索引为主键主键的选择根据的是定义索引的顺序,而不是建表时列的顺序。

InnoDB逻辑存储结构

从 InnoDB存储引擎的逻辑存储结构看,所有数据都被逻辑地存放在一个空间中,称之为表空间( tablespace)表空间又由段( segment)、区( extent)、页(page)组成。

表空间

表空间可以看做是 InnoDB存储引擎逻辑结构的最高层,所有的数据都存放在表空间中,即.idb文件。

每张表的独立表空间内存放的只是数据、索引和插入缓冲 Bitmap页,其他类的数据,如回滚(undo)信息,插人缓冲索引页、系统事务信息,二次写缓冲( Double write buffer)等还是存放在原来的共享表空间内。

常见的段有数据段、索引段、回滚段等。

  1. 数据段即为B+树的叶子节点(Leaf node segment)
  2. 索引段即为B+树的非索引节点(Non-leaf node segment)
  3. 回滚段(undo log)

在每个段开始时,先用32个页大小的碎片页来存放数据,在使用完这些页之后才是64个连续页的申请。

区是由连续页组成的空间,在任何情况下每个区的大小都为MB

为了保证区中页的连续性, InnoDB存储引擎一次从磁盘申请4~5个区。

在默认情况下, InnoDB存储引擎页的大小为16KB,即一个区中一共有64个连续的页。

页是InnoDB磁盘管理的最小单位。

在 InnoDe存储引擎中,默认每个页的大小为16KB。

在 InnoDB存储引擎中,常见的页类型有:

  1. 数据页(B-tree Node)
  2. undo页( undo Log Page
  3. 系统页( System Page)
  4. 事务数据页( Transaction system Page)
  5. 插入缓冲位图页( Insert Buffer Bitmap)
  6. 插入缓冲空闲列表页( Insert Buffer Free List)
  7. 未压缩的二进制大对象页( Uncompressed BLOB Page)
  8. 压缩的二进制大对象页( compressed BLOB Page)

InnoDB存储引擎中数据是按行进行存放的。

每个页存放的行记录也是有硬性定义的,最多允许存放16KB/2-200行的记录,即7992行记录。

出于性能考虑,一页中太多行数据性能不好

InnoDB行记录格式

行记录格式类型

  1. Redundant (mysql5.0之前)
  2. Compact (mysql5.0开始加入)
  3. Compressed (InnoDB 1.0.x开始)
  4. Dynamic (InnoDB 1.0.x开始)

以前支持的 Compact和 Redundant格式称为 Antelope文件格式,新的文件格式称为 Barracuda文件格式

Barracuda文件格式下拥有两种新的行记录格式: Compressed和 Dynamic 新的两种记录格式对于存放在BLOB中的数据采用了完全的行溢出的方式,在数据页中只存放20个字节的指针,实际的数据都存放在 Off Page中,

之前的Compact和 Redundant两种格式会存放768个前缀字节。

Compressed行记录格式的另一个功能就是,存储在其中的行数据会以zlib的算法进行压缩,因此对于BLOB、TEXT、 VARCHAR这类大长度类型的数据能够进行非常有效的存储。

VARCHAR(N)中的N指的是字符的长度,而文档中说明VARCHAR类型最大支持65535,单位是字节。(不同的编码方式会影响最大长度)

MySQL官方手册中定义的65535度是指所有VARCHAR列的长度总和,如果列的长度总和超出这个长度,依然无法创建表。

InnoDB 数据页结构

File Header

File header用来记录页的一些头信息,共占用38字节

接着 File header部分的是 Page Header,该部分用来记录数据页的状态信息,由14个部分组成,共占用56字节。

Infimum 和 Supremum Record

在 InnoDB存储引擎中,每个数据页中有两个虚拟的行记录,用来限定记录的边界。

Infimum记录是比该页中任何主键值都要小的值
Supremum指比任何可能大的值还要大的值
两个值在页创建时被建立,并且在任何情况下不会被删除

User Record 和 Free Space

User record就实际存储行记录的内容。

Free Space很明显指的就是空闲空间,同样也是个链表数据结构。在一条记录被删除后,该空间会被加入到空闲链表中。

Page Directory(页目录)

Page Directory页叫做页目录,存放了记录的相对位置,有些时候这些记录指针称为 槽 (Slots)或目录槽( Directory Slots)。

InnoDB存储引擎的槽是一个稀疏目录( sparse directory),即一个槽中可能包含多个记录。当记录被插人或删除时需要对槽进行分裂或平衡的维护操作。

在Slots中记录按照索引键值顺序存放,这样可以利用二叉查找迅速找到记录的指针。

B+树索引本身并不能找到具体的一条记录,能找到只是该记录所在的页!!!

**数据库把页载入到内存,然后通过Page Directory再进行二叉查找。**只不过二叉查找的时间复杂度很低,同时在内存中的查找很快,因此通常忽略这部分查找所用的时间。

槽细节深入

  1. 将所有正常的记录(包括最大和最小记录,不包括标记为已删除的记录)划分为几个组。
  2. 每个组的最后一条记录的头信息中的n_owned属性表示该组内共有几条记录。
  3. 将每个组的最后一条记录的地址偏移量按顺序存储起来,每个地址偏移量也被称为一个槽(英文名:Slot)。这些地址偏移量都会被存储到靠近页的尾部的地方,页中存储地址偏移量的部分也被称为Page Directory 。

InnoDB 对每个分组中的记录条数是有规定的,对于最小记录所在的分组只能有 1 条记录,最大记录所在的分组拥有的记录条数只能在 18 条之间,剩下的分组中记录的条数范围只能在是 48 条之间。

所以在一个数据页中查找指定主键值的记录的过程分为两步:

  1. 通过二分法确定该记录所在的槽。
  2. 通过记录的next_record属性组成的链表遍历查找该槽中的各个记录。

参考博客InnoDB数据页结构

File Trailer

为了检测页是否已经完整地写人磁盘(如可能发生的写入过程中磁盘损坏、机器关机等), InnoDB存储引擎的页中设置了 File trailer部分。

  • 前四个字节代表页的检验和
  • 后四个字节代表日志序列位置(LSN)