Mysql中每一行的实际数据在磁盘上是如何存储的?

一行数据在磁盘文件里存储的时候,实际上首先会包含自己的变长字段的长度列表,然后是 NULL值列表,接着是数据头,然后接着才是真实数据,所以讲讲真实数据是如何存储的。

首先我们在存储真实数据的时候,按照字段里的数据值去存储。

比如有一行数据是“jack NULL m NULL xx_school”,那么他真实存储大致如下所示:

0x09 0x04 00000101 0000000000000000000010000000000000011001 jack m xx_school

刚开始先是他的变长字段的长度,用十六进制来存储,然后是NULL值列表,指出了谁是NULL,接着是40个bit位的数据头,然后是真实的数据值,就放在后面。

在读取这个数据的时候,他会根据变长字段的长度,先读取出来jack这个值,因为他的长度是4,就读取4个长度的数据,jack就出来了;

  然后发现第二个字段是NULL,就不用读取了;

  第三个字段是定长字段,直接读取1个字符就可以了,就是m这个值;

  第四个字段是NULL,不用读取了;

  第五个字段是变长字段长度是9,读取出来xx_school就可以了。

但是,大家觉得真正在磁盘上存储的时候,我们那些字符串就是直接这么存储在磁盘上吗?

显然不是的! 实际上字符串这些东西都是根据数据库指定的字符集编码,进行编码之后再存储的,所以大致看起来一行数据是如下所示的:

0x09 0x04 00000101 0000000000000000000010000000000000011001 616161 636320 6262626262

我们的字符串和其他类型的数值最终都会根据字符集编码,搞成一些数字和符号存储在磁盘上 。

所以其实一行数据是如何存储的,我相信大家就都已经了解的很清晰了,给大家简单提一下,在实际存储一行数据的时候,会在他的真实数据部分,加入一些隐藏字段,这个隐藏字段跟后续的一些内容是有关联的。 首先有一个DB_ROW_ID字段,这就是一个行的唯一标识,是他数据库内部给你搞的一个标识,不是你的主键ID字段。如果我们没有指定主键和unique key唯一索引的时候,他就内部自动加一个ROW_ID作为主键。

接着是一个DB_TRX_ID字段,这是跟事务相关的,他是说这是哪个事务更新的数据,这是事务ID,这个后续我们讲解到事务的时候会跟大家说的。

最后是DB_ROLL_PTR字段,这是回滚指针,是用来进行事务回滚的,也是我们后续在讲解事务的时候再详细说。 所以如果你加上这几个隐藏字段之后,实际一行数据可能看起来如下所示:

0x09 0x04 00000101 0000000000000000000010000000000000011001 00000000094C(DB_ROW_ID)
00000000032D(DB_TRX_ID) EA000010078E(DB_ROL_PTR) 616161 636320 6262626262

我给上面几个隐藏字段都加了括号说明了,上面那基本就是最终在磁盘上一行数据是长成什么样的了

我们再看看下面的图,当你执行crud的时候,

  先会把磁盘上的数据加载到Buffer Pool里缓存,

  然后更新的时候也是更新Buffer Pool的缓存,同时维护一堆链表。

  然后定时或者不定时的,根据flush链表和lru链表,Buffer Pool里的更新过的脏数据就会刷新到磁盘上去。

 

 

 

现在我们思考一下,在磁盘上的数据,每一行数据是不是就是类似“0x09 0x04 000001010000000000000000000010000000000000011001 00000000094C(DB_ROW_ID)00000000032D(DB_TRX_ID) EA000010078E(DB_ROL_PTR) 616161 636320 6262626262”这样的东西?

现在我们初步的把磁盘上的数据和内存里的数据给关联起来了,他每一行数据的真实存储结构就了解了,屡清楚这个他们之间的关系,其实这些都是有机一体的 。

posted @ 2020-05-30 23:19  wxlevel  阅读(1898)  评论(0编辑  收藏  举报