InnoDB表存储格式

InnoDB

InnoDB引擎作为现在mysql的默认引擎,支持事务处理与外键约束,并且有很高的性能.今天这里来说一下InnoDB存储引擎中表的存储格式.

索引组织表

在InnoDB中,表都是根据主键顺序组织存放的.在InnoDB引擎中,每个表都有一个主键,如果在创建表的时候没有显示定义,则将表中的第一个非空唯一索引设为主键,如果没有这样的索引,则会自动创建一个6字节大小的指针.
看一个例子:

1
2
3
4
5
6
7
8
 mysql> create table t( a int not null, unique key(a) );
mysql> insert into t select 1;
mysql> select _rowid from t;
+--------+
| _rowid |
+--------+
| 1 |
+--------+

这里没有定义主键,会将第一个唯一非空索引设置为主键.也就是a作为主键.

逻辑存储结构

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

表空间

表空间可以看做是InnoDB存储引擎逻辑结构的最高层,所有的数据都被存放在表空间中.InnoDB引擎中有一个参数innodb_file_per_table,用来设置表空间的.如果开启了此参数,每张表内的数据可以单独放在一个表空间内,如果没开,则所有的表共享一个表空间.

上图说明了表空间是由各个段组成的,常见的段有数据段,索引段,回滚段.在InnoDB中,表是索引组织的,因此就是索引就是数据.
就是数据段即为B+树上的叶子节点.索引段就是B+树上的非叶子节点.

区是由连续的页组成的空间.在任何情况下每个区的大小都是1MB.默认情况下,InnoDB引擎中的页大小为16KB,即一个区中一共有64个连续的页.在InnoDB1.2.x版本中增加了innodb_page_size参数,该参数可以将默认的页大小设置为4K,8K,但是页中的数据库不压缩,这时候区中页的数量变为256,128.
这里有一个问题就是当启用了innodb_file_per_table后,创建的表的默认大小是96KB,区是连续的64个页,创建的表大小至少应该是1MB才对.这是因为在每个段开始的时候,先用32个页大小的碎片页来存放数据,在使用完这些页之后才是64个连续页的申请.这主要是对于一些小表或者undo这类的段,可以在开始时候申请较少的空间,节省磁盘容量的开销.

页是InnoDB磁盘管理的最小单位,在InnoDB引擎中,默认每个页的大小为16KB.
在InnoDB存储引擎中,常见的页类型有:

  • 数据页
  • undo页
  • 系统页
  • 事务数据页
  • 插入缓冲位图页
  • 插入缓冲空闲列表页
  • 未压缩的二进制大对象页
  • 压缩的二进制大对象页

数据页结构

InnoDB数据页由一下7个部分组成.

  • File Header 文件头 38字节
  • Page Header (页头) 56字节
  • Infimun和Supremum Records
  • User Records(用户记录,就是行记录)
  • Free Space(空闲空间)
  • Page Directory(页目录)
  • File Trailer(文件结尾信息)

File Header

File Header用来记录页的一些头信息.包含此页的一些头信息.

Page Header

Infimum 和 Supremum Record

在InnoDB存储引擎中,每个数据页中有两个虚拟的行记录,用来限定边界.Infimum记录的是比该页中任何主键值都要小的值,Supremum是比任何可能值都要大的值.这俩值在页创建时被简历,并且在任何情况下都不会被删除.

User Record 和Free Space

User Record就是实际存储行记录的内容.在InnoDB中,每个行记录都会存储下一条记录的相对位置.因此这里存储的行记录可以想成是一个链表数据结构.
Free Space则就是空闲空间,同样也是链表数据结构.在一条记录被删除后,该空间会被加入空闲链表中.

Page Directory

页目录中存放了记录的相对位置.有时候这些记录指针称为Slots(槽)或者目录槽.但是在InnoDB中并不是每个记录一个槽,这里的槽是个稀疏目录,即一个槽中可能有多个记录.每个记录都有一个n_owned的值,记录此记录所在槽中有多少个记录.伪记录Infimum的n_owned值总是1,记录Supremum的n_owned的取值范围为[1,8],当记录被插入或删除的时候需要对槽进行分裂或平衡的维护操作.
在Slots中记录按照索引键值顺序存放,这样利用二叉查找迅速找到记录的指针.由于Slots是一个稀疏目录,所以二叉查找是一个粗略的结果,之后在根据记录的下一个指针继续查找相关的记录.

File Trailer

为了检测页是否已经完整的写入磁盘(如可能发生的写入过程中磁盘损坏,机器关机等),InnoDB存储引擎的也中设置了File Trailer部分.File Trailer中只有一个FIL_PAGE_END_LSN部分,占用8字节.前4字节代表该页的checksum值,最后四字节和FileHeader中的FIL_PAGE_LSN相同.将这两个值与FileHeader中的两个值相比,是否一致,(这里checksum的比较需要通过InnoDB的checksum函数来进行比较,不是简单的等值比较),以此来保证页的完整性.