0%

MYSQL-InnoDB存储

MySQL存储结构

InnoDB存储

表->段->区->页->行

在数据库中,不论读哪一行数据,还是读多行数据,都是将这些行所在的页进行加载。也就是存储空间的基本单位就是页。

一个页就是一颗B+树的节点,数据库I/O操作的最小单位是页,与数据库相关的内容都会存储在页的结构里。

1629471915

Table Space

表空间,数据存储为 三个段(segment)

Segment

Leaf node segment

  • 叶结点段

    存储数据记录

Non-Leaf node segment

  • 非叶子结点段

    存储索引:主键索引,辅助索引

Rollback segment

  • 回滚段

    存储事务回滚数据(维护不同事务的独立视图,记录事务所有过程)

Page (Special)

  • 当表数据非常小时,实际上没有Extent

    因为表数据小时 (小于1M) 生成Extent时会造成空间浪费,因此在这种情况下会直接将Page存在Segment中。

  • 通常32个Page,当32个Page塞满时,开始扩增第一个Extent

Extent

一个表区分为三个段,每段内部结构类似,内部分为若干个 区(Extent) ,每个区默认大小1MB的

表数据容量扩增基本单位就是 Extent

Page

每个 区(Extent) 中包含若干个 页(Page),每个Page默认大小16K,因此一个Extent默认下为64个Page,即默认情况下每次扩增Extent增加64个Page

Page 中存储记录,因为每条记录不等长,因此16K可以存放若干条记录

当表记录非常少或零碎数据时,Page会直接在 段(Segment) 中生成,而非生成一个Page,节约空间占用(一般32个Page)

  • 整个MySQL是以 Page 作为单位管理的

    MySQL设计是读取数据是以磁碟结构为基础设计的,当只读取一条时磁头以Row为单位移动不划算,因此以一个Page(16K)为基准一次读取,再筛选需要的数据

Page

  • 控制信息

Row

  • 数据记录

    理想状态下是主键顺序存储,但主键可以不按顺序插入数据

  • 指针

    为了保证顺序,每一行都有一个指针(单向链表)

Page Directory

Slot Slot Slot Slot Slot Slot Slot
1 指向页中的行地址 2,3 指向页中的行地址 4 指向页中的行地址
  • 严格按照主键递增顺序存储Directory

  • 当读取Page时,即可获取到Page Directory,迅速获取Row数据

    获取方式:二分法

  • 每个Slot可能存储不止一条Row

    若只有一条Row,则查询性能高,但会导致Page Directory过长,若多条数据则寻道时间长,易与业务性能要求冲突,需根据业务需求设计Row大小 (建议Page使用默认值16K)

Row

数据记录

页合并与分裂

页分裂

页可能填充至100%,在页填满了之后,下一页会继续接管新的记录。但如果没有足够空间去容纳新(或更新)的记录时,需在页中间插入数据,此时会触发页分裂。

InnoDB的做法:

  1. 创建新页
  2. 判断当前页可以从哪里进行分裂(记录行层面)
  3. 移动记录行
  4. 重新定义页之间的关系

Insert

页合并

当你删了一行记录时,实际上记录并没有被物理删除,记录被标记(flaged)为删除并且它的空间变得允许被其他记录声明使用。

当页中删除的记录达到MERGE_THRESHOLD(默认页体积的50%),InnoDB会开始寻找最靠近的页(前或后)看看是否可以将两个页合并以优化空间使用。

页合并发生在删除或更新操作中,关联到当前页的相邻页。如果页合并成功,在INFOMATION_SCHEMA.INNODB_METRICS中的index_page_merge_successful将会增加。

DEL_UPDATE

因此不建议使用非主键记录,因为乱序问题可能导致页分裂频繁。同时不建议使用物理删除,因为会导致页合并(推荐使用逻辑删除,若逻辑删除导致空间不足,应申请窗口维护期统一物理删除数据)。

来源:

https://www.icourse163.org/learn/XMU-1462056168

https://zhuanlan.zhihu.com/p/98818611