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”
这样的东西?
所以现在我们就初步的把磁盘上的数据和内存里的数据给关联起来了,他每一行数据的真实存储结构我们就了解了,屡清楚这个他们之间的关系,其实这些都是有机一体的 。