InnoDB-Disk IO & File Space

空间管理

InnoDB Disk I/O

InnoDB使用异步磁盘IO,创建许多控制IO操作的进程,从而在进行其他数据库操作的同时依然能够把内容写到磁盘里。在进程内部,写入操作依然是同步的,并不是使用系统原生的异步IO API。

Read-Ahead

InnoDB认为部分数据有可能会很快用到时,会将其从磁盘载入内存中(Buffer Pool),为实现大块连续读,InnoDB有两种策略

  • 连续Read-Ahead,如果InnoDB注意到相关语句对某个tablespace的段访问是连续的,它会将整段内容提前载入到内存中
  • 随机Read-Ahead,如果InnoDB注意到直接载入一整个tablespace会更快,它会直接把整个tablespace载入内存

Doublewrite Buffer

见前文中有关内容

File Space Management

InnoDB中的数据库存在文件中,所有内容写在一个文件还是分开写,都使用tablespaces的配置决定

Pages, Extents, Segments, and Tablespaces

Page

Page是数据库的最小磁盘空间管理单位,其尺寸默认为16K,可以修改。其结构为

名称 长度/字节 说明
File Header 38 页的通用信息
Page Header 56 数据页专有信息
Infimum+supremum 26 两个虚拟行记录
User Records Not Fix 实际存储的行记录
Free Space Not Fix 空闲空间
Page Directory Not Fix 某些记录的相对位置
File Tail 8 校验

Extents

Extents是由许多Page组成的空间管理单位,其尺寸对照表如下

Page尺寸 Extent尺寸 Extent中的Page数
4K 1M 256
8K 1M 128
16K 1M 64
32K 2M 64
64K 4M 64

Segment

Segment是由Extent构成的更高一级的单位。在InnoDB中,Tablespace的“文件”被称为Segment,注意,这个Segment和Rollback Segment什么的不一样,但是Rollback Segment会包含很多个Tablespace中的Segment。当Segment的空间不足时,InnoDB会先申请32 Pages,如果还需要申请,则会申请1个Extent。当Segment变得过大,InnoDB会一次获取4个Extents以保证数据的连续性。

一个Tablespace中包含两个Segment,一个用于存非叶子节点,一个用于存叶子节点,以保证叶子节点读写的连续性。

一些Page保存的是其他page的bitmap,所以有的时候Segment中只会包含零散的几个页而非整Extent。

删除操作的时候,会依据是否释放整Page或是整Extent来决定释放空间;删除表和行可以释放空间,但只在purge后空间才会被释放。

Page and Row

最长的行长度应当小于页的一半,如果出现过长的行,该行会被存在扩展页外存储(External off-page)中,直到其长度能被一页存下再挪回页中。

Row

行结构

  • 变长字段长度列表: 存储着所有变长字段的数据占用的字段长度
  • NULL标志位: 可以为NULL的列与标记为NULL的列
  • 记录头信息
  • 列1
  • 列2

记录头信息格式如下

名称 大小/bit 描述
预留位 2 没用
delete_mask 1 删除标记
min_rec_mask 1 非叶子节点中的最小记录
n_owned 4 当前记录的记录数
heap_no 13 当前记录在堆中的位置信息
record_type 3 记录类型,0:叶节点,1:非叶子节点,2:最小记录,3:最大记录
next_record 16 下一条记录的相对位置

External off-page

  • COMPACT and REDUNDANT: 当数据在Page中放不下时,InnoDB会在Page中存前768个字节,并将其他数据存到溢出页中,每个列都有自己的溢出页。该768个字符的前20个记录了该数据的长度以及多于内容在溢出页中的指针。
  • DYNAMIC and COMPRESSED: InnoDB只会在Page内存20个字符的内容,表示长度和指针。

Checkpoints

InnoDB只会小批量地将Buffer Pool中的内容写到磁盘中以避免对用户体验造成影响。

ref