innodb引擎底层存储结构【Mysql Day 1】

118 阅读4分钟

数据库表中的一行行记录是怎么存储的呢?【行记录】

下面介绍一下重要的属性【compact记录结构】:

  • 记录头信息:
    • delete_mask:是否删除的标识
    • min rec mask:B+树的每层非叶子节点中的最小记录都会添加该标记
    • n owned:表示当前记录有几个列
    • heap_no:表示当前记录在页的位置信息,分配了heap_no之后,值不会改变了,即使删除了堆中的某条记录
    • record_type:表示当前记录的类型
    • next_record:当前记录的真实数据到下一条记录的真实数据的距离,通过该属性将一个个记录串成单链表
    • DB_ROW_ID(row_id):非必须,6字节,表示行ID,唯一标识一条记录【没定义主键,就用的这个】
    • DB_TRX_ID:必须,6字节,表示事务ID
    • DB_ROLL_PTR:必须,7字节,表示回滚指针

一系列连接起来的记录称之为堆(heap),其中堆的开始是从infimum开始,其余记录从heap_no= 1开始  以supremum标记记录的最大值
(一个头,一个尾)

如何管理这些行记录呢 ----【数据页】

数据页数据结构

介绍几个重点属性:

  1. infimum :记录的起始边界

  2. supremum :记录的结束边界

  3. user records:真正存记录的地

  4. page directory【记录的索引】:有好多槽位,一个槽位管几个行记录,通过二分法定位到某个行记录,然后通过行记录的记录头信息的next_record像单链表一样遍历,遍历次数就是记录头信息的n owned的值

如何快速定位数据页中的记录呢?----【索引】

为数据页建立索引,建立特殊的数据页--【目录页记录】,再为目录页再建立索引,如此反复则建立了b+树这个数据结构

这次只唠唠innodb的存储结构,索引后面再唠

如何管理这么多的数据页呢?【区->组->段->表空间】

为什么要引入区的概念?

方便管理,当表中数据很大时,为某个索引分配空间则以区为单位去分配而不是以页分配,以区为单位去读取数据,一个区64个连续的页,默认占用1MB大小,尽可能将随机IO变为顺序IO

区的分类

  • 空闲的区free
  • 有剩余空闲页面的碎片区free_frag
  • 没有剩余空闲页面的碎片区full_frag
  • 附属于某个段的区fseg

区的管理

XDES Entry 数据结构:每一个XDES Entry对应一个区

重点属性

List Node :可以将若干个XDES Entry 数据结构【区】串成一个双向链表,将三种链表串起来free链表free_frag链表full_frag链表,你或许想问这三个链表的头节点在哪记录啊?稍等片刻,其实是在INODE Entry结构【段】中的list base node属性中记录了,继续往后看!

1、每个段都建立这三种链表
2、每个索引对应两个段,每个段3个上述链表

每256个区又被划分成一个组

某些零散的页面【碎片区】以及一些完整的区的集合。

  • 标准区:存储同一个段的数据
  • 碎片区东拼西凑的:以区为单位给段分配空间对于那些数据量小的,太奢侈了,将这些页面拼凑成一个碎片区,当某个段占用了32个碎片区之后,则就会以完整的区为单位分配存储空间

分类

  • 数据段叶子节点段
  • 索引段非叶子节点段
  • 回滚段

INODE Entry结构

  • list base node 记录了三个链表的头节点

表空间

  • 表空间想象成被切分为许许多多个页的池子,当我们想为某个表插入一条记录的时候,就从池子中捞出一个对应的页来把数据写进去
  • 一个表空间最多支持64TB的数据

总结

  1. 表空间被划分成许多连续的区,每个区默认由64个页【一个页默认16KB】 也就是1MB组成
  2. 每256个区【256MB】划分为一个组,每个组最开始的几个页面是固定的类型 【FSP_HDR类型】【IBUF_BITMAP类型页】【INODE类型页】
  3. 段是一个逻辑上的概念,是一些零散的页面以及一些完整区的集合【杂牌军+正规军】
  4. 每个段对应一个INODE Entry结构,该结构存了一些与这个段相关的属性【三种链表的起始点】
  5. 每个区对应一个XDES Entry结构,该结构里有一个list node属性,会连接3种链表【代表三种页面状态的集合】FREE、NOT_FULL、FULL链表