索引组织表
在 InnoDB存储引擎中,表都是根据主键顺序组织存放的,这种存储方式的表称
为索引组织表( index organized table)。
在 InnoDB存储引擎表中,每张表都有个主键( Primary Key),如果在创建表时没有显式地定义主键,则InnoDB存储引擎会按如下方式选择或创建主键:
- 首先判断表中是否有非空的唯一索引( Unique NOT NULI),如果有,则该列即为主键。
- 如果不符合上述条件, InnoDB存储引擎自动创建一个6字节大小的指针。
当表中有多个非空唯一索引时, InnoDB存储引擎将选择建表时第一个定义的非空唯索引为主键。主键的选择根据的是定义索引的顺序,而不是建表时列的顺序。
InnoDB逻辑存储结构
从 InnoDB存储引擎的逻辑存储结构看,所有数据都被逻辑地存放在一个空间中,称之为表空间( tablespace)。表空间又由段( segment)、区( extent)、页(page)组成。

表空间
表空间可以看做是 InnoDB存储引擎逻辑结构的最高层,所有的数据都存放在表空间中,即.idb文件。
每张表的独立表空间内存放的只是数据、索引和插入缓冲 Bitmap页,其他类的数据,如回滚(undo)信息,插人缓冲索引页、系统事务信息,二次写缓冲( Double write buffer)等还是存放在原来的共享表空间内。
段
常见的段有数据段、索引段、回滚段等。
- 数据段即为B+树的叶子节点(Leaf node segment)
- 索引段即为B+树的非索引节点(Non-leaf node segment)
- 回滚段(undo log)
在每个段开始时,先用32个页大小的碎片页来存放数据,在使用完这些页之后才是64个连续页的申请。
区
区是由连续页组成的空间,在任何情况下每个区的大小都为MB。
为了保证区中页的连续性, InnoDB存储引擎一次从磁盘申请4~5个区。
在默认情况下, InnoDB存储引擎页的大小为16KB,即一个区中一共有64个连续的页。
页
页是InnoDB磁盘管理的最小单位。
在 InnoDe存储引擎中,默认每个页的大小为16KB。
在 InnoDB存储引擎中,常见的页类型有:
- 数据页(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)
行
InnoDB存储引擎中数据是按行进行存放的。
每个页存放的行记录也是有硬性定义的,最多允许存放16KB/2-200行的记录,即7992行记录。
出于性能考虑,一页中太多行数据性能不好
InnoDB行记录格式
行记录格式类型
- Redundant (mysql5.0之前)
- Compact (mysql5.0开始加入)
- Compressed (InnoDB 1.0.x开始)
- 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字节
Page Header
接着 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再进行二叉查找。**只不过二叉查找的时间复杂度很低,同时在内存中的查找很快,因此通常忽略这部分查找所用的时间。
槽细节深入
- 将所有正常的记录(包括最大和最小记录,不包括标记为已删除的记录)划分为几个组。
- 每个组的最后一条记录的头信息中的n_owned属性表示该组内共有几条记录。
- 将每个组的最后一条记录的地址偏移量按顺序存储起来,每个地址偏移量也被称为一个槽(英文名:Slot)。这些地址偏移量都会被存储到靠近页的尾部的地方,页中存储地址偏移量的部分也被称为Page Directory 。
InnoDB 对每个分组中的记录条数是有规定的,对于最小记录所在的分组只能有 1 条记录,最大记录所在的分组拥有的记录条数只能在 18 条之间,剩下的分组中记录的条数范围只能在是 48 条之间。

所以在一个数据页中查找指定主键值的记录的过程分为两步:
- 通过二分法确定该记录所在的槽。
- 通过记录的next_record属性组成的链表遍历查找该槽中的各个记录。
参考博客InnoDB数据页结构
File Trailer
为了检测页是否已经完整地写人磁盘(如可能发生的写入过程中磁盘损坏、机器关机等), InnoDB存储引擎的页中设置了 File trailer部分。
- 前四个字节代表页的检验和
- 后四个字节代表日志序列位置(LSN)