NOTE

1.12 MySQL页

1. 行格式 - Record(Row、记录)在磁盘上存放的格式 1.1. Compact 1.1.1. 记录的额外信息 1.1.1.1. 变长字段长度列表 - 比如varchar(100)、blob、text,会把长度记录在这里 1.1.1.2. NULL值列表 - 使用bit记录列是否为NULL

MySQL / Database创建于 更新于 historical

这是历史学习笔记,可能存在过时或不完整的理解。

1. 行格式

  • Record(Row、记录)在磁盘上存放的格式

1.1. Compact

1.1.1. 记录的额外信息

1.1.1.1. 变长字段长度列表
  • 比如varchar(100)、blob、text,会把长度记录在这里
1.1.1.2. NULL值列表
  • 使用bit记录列是否为NULL。列为NULL则为1,否则为0
1.1.1.3. 记录头信息
名称 占用bit 描述
预留位1 1 没有使用
预留位2 1 没有使用
delete_mask 1 标记该记录是否被删除
min_rec_mask 1 B+树的每层非叶子节点中的最小记录都会添加该标记
n_owned 4 表示当前记录拥有的记录数
heap_no 13 表示当前记录在记录堆的位置信息
record_type 3 表示当前记录的类型, 0 表示普通记录, 1 表示B+树非叶子节点记录, 2 表示最小记录, 3表示最大记录
next_record 16 表示下一条记录的相对位置
1.1.1.3.1. delete_mask
  • 被删除的记录不会真的物理删除,而是逻辑删除
  • 所有被删除掉的记录都会组成一个所谓的 垃圾链表 ,在这个链表中的记录占用的空间称之为所谓的 可重用空间 ,之后如果有新记录插入到表中的话,可能把这些被删除的记录占用的存储空间覆盖掉
  • 这也就意味着删除之后不会释放空间
    • 可以使用optimize table table_name 释放磁盘空间
1.1.1.3.2. min_rec_mask
  • B+树的每层非叶子节点中的最小记录都会添加该标记
1.1.1.3.3. next_record
  • 从当前记录的真实数据到下一条记录的真实数据的地址偏移量。说白了我们的记录按照主键从小到大的顺序形成了一个单链表
1.1.1.3.4. heap_no
  • 表示当前记录在本页中的位置。比如2、3、4、5。至于0和1则是最小记录和最大记录
1.1.1.3.5. record_type
  • 表示当前记录的类型,一共有4种类型的记录, 0 表示普通记录, 1 表示B+树非叶节点记录, 2 表示最小记录, 3 表示最大记录

1.1.2. 记录的真实数据

  • row_id
  • transaction_id
  • roll_pointer
  • 列1的值
  • 列2的值

1.2. Redundant

  • MySQL5.0 之前用的一种行格式

1.3. Dynamic

  • MySQL5.7的默认格式
  • 与Compact一样,区别在于处理行溢出的数据
    • 不会在记录的真实数据处存储字段真实数据的前 768 个字节,而是把所有的字节都存储到其他页面中,只在记录的真实数据处存储其他页面的地方
    • 行溢出
      • 一个页面能存储16KB的数据,当记录中的数据太多,当前页放不下的时候,会把多余的数据存储到其他页中,这种现象称为行溢出

1.4. Compressed

与Dynamic一样,区别在于会采用压缩算法对页面进行压缩

2. 页

  • InnoDB或MyISAM管理存储空间的基本单位,一个页的大小一般是 16KB

2.1. 数据页

名称 中文名 占用空间大小 简单描述
File Header 文件头部 38 字节 页的一些通用信息
Page Header 页面头部 56 字节 数据页专有的一些信息
Infimum + Supremum 最小记录和最大记录 26 字节 两个虚拟的行记录
User Records 用户记录 不确定 实际存储的行记录内容
Free Space 空闲空间 不确定 页中尚未使用的空间
Page Directory 页面目录 不确定 页中的某些记录的相对位置
File Trailer 文件尾部 8 字节 校验页是否完整

2.1.1. File Header

  • 所有类型的页通用
名称 占用空间大小(Byte) 简单描述
FIL_PAGE_SPACE_OR_CHKSUM 4 页的校验和(checksum值)
FIL_PAGE_OFFSET 4 页号
FIL_PAGE_PREV 4 上一个页的页号
FIL_PAGE_NEXT 4 下一个页的页号
FIL_PAGE_LSN 8 页面被最后修改时对应的日志序列位置(英文名是:Log Sequence Number)
FIL_PAGE_TYPE 2 该页的类型
FIL_PAGE_FILE_FLUSH_LSN 8 仅在系统表空间的一个页中定义,代表文件至少被刷新到了对应的LSN值
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID 4 页属于哪个表空间
  • FIL_PAGE_PREV 和 FIL_PAGE_NEXT:
    • 只有INDEX类型的页,也就是数据页才有这两个
    • 分别代表本页的上一个和下一个页的页号
    • 使用双向链表把多个页串起来
  • FIL_PAGE_OFFSET:
    • 每一个 页 都有一个单独的页号
    • 由4Bytes组成,也就是说表空间可以存放2^32个页,每个页16KB,那么一个表空间最大64TB
  • FIL_PAGE_TYPE:
    • 当前 页 的类型
    • 比如存放记录的数据页的类型其实是 FIL_PAGE_INDEX ,也就是所谓的 索引页

2.1.2. Page Header

  • 数据页中存储的记录的状态信息,比如本页中已经存储了多少条记录,第一条记录的地址是什么,页目录中存储了多少个槽等等
名称 占用空间大小(Byte) 简单描述
PAGE_N_DIR_SLOTS 2 在页目录中的槽数量
PAGE_HEAP_TOP 2 还未使用的空间最小地址,也就是说从该地址之后就是 Free Space
PAGE_N_HEAP 2 本页中的记录的数量(包括最小和最大记录以及标记为删除的记录)
PAGE_FREE 2 第一个已经标记为删除的记录地址(各个已删除的记录通过 next_record 也会组成一个单链表,这个单链表中的记录可以被重新利用)
PAGE_GARBAGE 2 已删除记录占用的字节数
PAGE_LAST_INSERT 2 最后插入记录的位置
PAGE_DIRECTION 2 记录插入的方向
PAGE_N_DIRECTION 2 一个方向连续插入的记录数量
PAGE_N_RECS 2 该页中记录的数量(不包括最小和最大记录以及被标记为删除的记录)
PAGE_MAX_TRX_ID 8 修改当前页的最大事务ID,该值仅在二级索引中定义
PAGE_LEVEL 2 当前页在B+树中所处的层级
PAGE_INDEX_ID 8 索引ID,表示当前页属于哪个索引
PAGE_BTR_SEG_LEAF 10 B+树叶子段的头部信息,仅在B+树的Root页定义
PAGE_BTR_SEG_TOP 10 B+树非叶子段的头部信息,仅在B+树的Root页定义
  • PAGE_DIRECTION:新插入的一条记录的主键值比上一条记录的主键值大,我们说这条记录的插入方向是右边,反之则是左边
  • PAGE_N_DIRECTION:假设连续几次插入新记录的方向都是一致的, InnoDB 会把沿着同一个方向插入记录的条数记下来,这个条数就用 PAGE_N_DIRECTION 这个状态表示
  • PAGE_N_DIR_SLOTS:在页目录中的槽数量
  • PAGE_LAST_INSERT:最后插入记录的位置
  • PAGE_N_RECS:该页中记录的数量(不包括最小和最大记录以及被标记为删除的记录)

2.1.3. User Records

  • 实际存储的行记录内容
  • User Records增长时Free Space会缩小

2.1.4. Free Space

  • 页中尚未使用的空间
  • User Records增长时Free Space会缩小

2.1.5. Page Directory

2.1.5.1. 为什么有Page Directory
  • 记录在页中按照主键值由小到大顺序串联成一个单链表,那如果我们想根据主键值查找页中的某条记录需要遍历链表查找,这个效率太慢了
2.1.5.2. Page Directory是什么
  • 将记录分组,每组的最后一条记录的地址存放在页目录中,叫做槽。其实就是目录
  • 在一个数据页中查找指定主键值的记录的过程分为两步
    • 通过二分法确定该记录所在的槽,并找到该槽中主键值最小的那条记录
    • 通过记录的 next_record 属性遍历该槽所在的组中的各个记录

2.1.6. File Trailer

2.1.6.1. 为什么有File Trailer
  • InnoDB以页为单位把磁盘数据加载到内存中处理,如果该页的数据在内存中修改了,需要把一段时间后把整页写回磁盘。但是如果在写回的过程中宕机了,那么数据就不正确了,于是为了检测一个页是否完整,在每个页的尾部都加了一个 File Trailer
2.1.6.2. File Trailer是什么
  • 所有类型的页通用

2.2. 索引页

2.2.1. 为什么需要索引页

Page Directory只能用于页内的主键进行快速查找,如果是非主键或者跨多个页就不行了

2.2.2. 索引页和数据页的关系

  • 也是用页存储,只不过User Record的record_type为1,表示目录项(即索引)
  • 一层目录:
  • 多层目录: