MysqlInnoDB存储引擎数据结构

磁盘存储的局部性原则

先来看一个基础查询语句

select * from a where c > 1;

分析一下sql的实现过程,按照通常理解,首先会找到c = 1的这条数据放到内存里,然后由cpu拿到c =1的这个值与c > 1的条件进行比较运算,然后逐条筛选符合条件的数据。这样的话显而易见查询结果的性能非常低下,因为要逐条从磁盘读取数据。所以为了避免这种状况,这时候操作系统会取此数据相邻的一些数据放入内存中,当下次有用到这些数据的时候直接从内存中去取而不用去读磁盘,这就是所谓的局部性原则。

局部性原理:一个良好的计算机程序 常常具有良好的局部性,也就是说,它们倾向于引用邻近于其他最近引用过的数据项的数据项,或者最近引用过的数据项本身。

那么问题来了,回到查询语句上,按照局部性原理,那么操作系统应该取多少数据缓存到内存中,这就引出了一个新的存储单位:。mysql的一行数据物理存储是具体存储到某一页上,所以操作系统会取出c=1的这行数据所在的页缓存到内存中,一页的大小默认为4kb

Innodb的存储结构

Innodb既然作为一个存储引擎,自然也会遵守局部性原则,innodb的页大小默认为16kb
innodb页的存储结构
如图,简单介绍一下

  • file header记录page的头部信息,重要的是里面存储了下个页的地址信息与上个页的地址信息,所以innodb页是一个双向链表。
  • page header 用于记录page的状态信息。
  • 第三行则是标明此页存储的最小和最大边界值,即存储在这页上的最小主键值要大于最小边界值小于最大边界值。
  • user records存储真正的mysql数据。
  • free space顾名思义,剩余空间
  • page directory 即目录,存储页中某些数据的相对位置
  • file trailer 校验页是否完整

行记录

mysql的数据都是按行存储的,所以存储到磁盘上也是有对应的行结构。

Compact 行记录

在这里插入图片描述

  • 变长字段长度列表:一到两个字节,逆序记录每一个列的长度。该字段的实际长度取决于列数和每一列的长度,因此是变长的。举例来说,varchar类型就是变长的,而int类型就是固长的。
  • NULL 标志位:一个字节,表示该行是否有 NULL 值。
  • 记录头信息:其中 next_record 记录了下一条记录的相对位置,一个页中的所有记录使用这个字段形成了一条单链表。
  • 列1,列2:即真正的sql列数据
  • 隐藏列: Transaction ID、Roll Pointer 以及 row_id(当没有指定主键)。
行溢出

除掉blob类型,mysql一行数据大小最大值是65535个字节,但并不代表你创建表给表中某个字段最大值为65535.。如下

crate table a (
c varchar(65535))

像这样则创建失败,因为行的最大长度65535包括的变长列表,null标志位等。

页溢出

我们知道数据页的大小是 16KB,如果一页当中的记录过大,则会进行分页处理,前页会存储下页地址。

索引

读者都知道innodb的索引数据结构为b+ 树。之前提到页的结构中介绍过page directory,mysql页中的数据是以主键递增单链表形式存储,而链表的缺点很明显,查询效率慢,所以page directory就为解决这种状况出现,将主键进行分组存储到目录中,再查询的时候利用二分法查询目录,确定要在哪组进行遍历,从而提升查询速度。

在这里插入图片描述
如图,假如查询8_1a 这条数据,先在目录进行比较,主键为8,在目录下比较后是大于4小于10,就去4目录分组下的去递归遍历。
这是一个页内的查找状况,但实际查询数据你无法你需要的数据确定在哪一页,这时候通过页内的目录查找思想灵活运用,即每页的页号会以k,v的形式存储,k为页内的最小主键值,v为页的实际存储地址。
即如图
在这里插入图片描述

b+ 树就是这样一个个节点累积而成的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值