MySQL数据库储存引擎Inoodb一--记录储存结构

  在开文我先说明一下,接下来的数据库知识文章都是在微信公众号“我们都是小青蛙”学习然后在通过自己的理解进行书写的。有兴趣的朋友可以去关注这个微信公众号。话不多说,我们在日常使用数据库进行数据持  久化的时候有没有想过我们的数据在数据库中是什么样的储存结构,我们可能想的最多的是怎样进行SQL的调优,但是对于数据库都不熟悉能做到调优设计么?答案显然是不能!!所以我们在这里开始数据库的第一  篇文章。数据库的记录储存结构。

  我们可能有很多熟悉的数据库储存引擎,比如说Inoodb,MyISAM,Memory。每一种储存引擎对于数据的持久化可能是不同的,比如说我们的Memory储存引擎的数据都是不会写进磁盘的,所有的数据是保存在内存  中的,也就意味着如果我们的服务器进行重启以后,数据是不会被进行保存的。当然,因为MySQL数据库默认的储存引擎是使用的Inoodb,所以我们在这里是需要重点介绍这个储存引擎的。

  简介:

    Inoodb储存引擎是把数据储存在磁盘里面的储存引擎,它在内存和磁盘的交互中使用的是页这个数据单位。我们都知道一个事情就是我们在对磁盘进行访问的时候速度是非常慢的,所以我们肯定是不能接受一      条数据一条数据的进行取用。所有数据划分为若干页,一个数据页是可以保存16kb的数据,也就是说我们每次在进行数据访问的时候是一次性的16kb数据。

  行格式:

    知道了数据库中我们数据的大概储存方式,那么接下来我们需要做的就是学习一条数据在我们的数据库中是什么样的一个结构存在。我们把数据库储存数据的格式称之为行格式或者是记录格式,我们现在所使用    的行格式有Compact,Redundant,Dynamic,Compressed。当然随着时间的迁移我们是会有更多的行格式出现。

  Compact:

    创建语法:我们会在bysj数据库中创建一个表,test,方便我们接下来对于储存结构的演示。如下所示,设置行格式我们直接使用ROW_FORMAT=行格式名称 。我们同时也对编码格式进行了设置为ASCII,这个    编码格式只能是储存空格,字母,标点符号,不可见字符,数字。所以汉字是不可以储存进来的!

    

    接下来我们插入两条数据:

    

    

    结构示意图:如下图所示我们可以看到的是分为两个大部分,第一部分就是记录额外信息,第二部分就是记录真实数据,接下来我们对这两个部分进行详细的描述:

    

    变长字段长度列表:

        这个部分记录的是可变长字段的信息,比如说VARCHAR,VARBINARY,各种TEXT,BLOB数据类型。我们都知道这些可变长的数据类型是分为两部分的,第一种就是它们可以储存的数据最大值,第二种      就是储存数据的真实大小。MySQL数据库也不知我们到底储存了多少内容,所以我们在变长字段长度列表里面是需要指出的。

        我们以第一条数据为例,我们知道C1,C2,C4是可变长的数据类型,C3不是,所以我们在这里是需要记录三列的储存情况。因为我们采用的是ASCII字符集,所以一个字符我们需要一个字节进行编       码。那么我来看看储存数据对应的长度表示:

        

        注意:我们在变长字段长度列表里面进行长度保存的时候是要根据列对应的逆序记性保存,并且只保存值为非NULL的列,所以我们这条数据在变长字段长度列表的表示如下图所示:

        

        因为数据都较短,所以在变长字段长度列表里面我们使用一个字节对这些信息进行保存,所以我们会产生疑问,在这里保存每一列的信息的时候怎么判断是使用的一个字节还是两个字节呢?三个因素:

          1>字符集储存一个字符使用字节M(我们采用的ASCII是1,UTF-8是3,GBK是2)

          2>可以储存的位数W(VARCHAR(W))

          3>真实储存的位数L

        规则:

          (1)当M * W < 256使用一个字节

          (2)当M * W > 256:L小于128使用一个字节,L大于128使用两个字节。

    NULL值列表:

      顾名思义这是用来储存除了NOT NULL,主键等关键字修饰的列的信息。因为我们的空值列如果进行储存的话也是需要消耗内存的,所以我们在这里进行记录,后面的真实数据就是不用进行保存的了。

      我们用第二条数据为例:因为C2是不能为空的,所以我们需要记录的是C1,C2,C3的信息:

          

      我们就来看看这个06数据到底是怎么一回事儿,这个值到底是怎么得到的:

        1>如果对应列值为空,那么我们用1进行表示,如果不为空那么我们就用0进行表示,每个列对应一个二进制位。

        2>和变长数据长度列表规则一致,我们必须是要使用列的逆序进行表示。

        3>如果使用的二进制位不是字节的整数倍,那么我们是需要在高位进行补零操作的。

      所以综合上述三条规则,我们是可以轻易的写出第二条数据在NULL列表里面的二进制位表示:0000 0110-->对应的十六进制就是:0x06,所以我们到这里就可以知道上面图片中的06是怎么得到的了。

   记录头信息:

      介绍完了前面的两个部分接下来就是我们数据额外信息板块的最后一个部分,记录头信息。这部分是5个字节,40个二进制位组成的,那么这40个二进制位分别代表了什么内容:

      

                

     预留位1  一:没有进行使用

     预留位2  一:没有进行使用

     delete_mask   一:是否被删除

     min_rec_mask  一:该记录是否为B+树中非叶子节点的最小记录

     n_owned  四: 当前嘈管理的记录数

     heap_no 十三:当前数据在记录堆的位置

     record type 三:0表示普通记录,1表示B+树非节点记录,2表示最小记录,3表示最大记录

     next_record  十六:下一条记录的相对位置

         

    

    上图就是我们两条记录对应的记录头信息,如果我们在这里记不住头信息的这些概念信息或者是看不懂上图,没关系,我们看一下就OK。后边会继续详细的讲解。

    记录的真实数据:

      记录的真实数据除了我们插入的那些数据列之外,MySQL数据库还会帮我们自动生成三个列,也称之为隐藏列。

      

      注意:行id不是必须有的,是在我们没有进行主键指定的时候才生成的。我们的事务id和回滚指针才是每一条数据都会帮助我们进行添加的。我们不需要关心这三个列的数据添加,因为是MySQL自动帮我们      进行添加的。

      我们看看加上真实数据以后,我们添加的两条记录的储存完整格式是什么情况:

      

      注意:

        1>在第一条数据中的C3列虽然真实储存的是 ‘cc’ 但是我们定义的数据类型是char,所以需要进行完整的表示它定义的十个字符空间,剩下的八个用空格字符进行填充。

        2>我们在第二条数据中看到的是C3,C4两个列是没有在真实数据中进行保存的,因为它们已经在NULL列表里面已经进行了储存声明,所以是不需要重复进行储存的。

        3>上边的数据储存因为我们采用的是ASCII字符集,当然如果采用其他的字符集是会不一致的。

  Redundant:

      这个行格式是MySQL5.0之前的版本使用的行格式,非常古老,但是我们还是介绍一下。直接进行和Compact行格式比较:

      结构示意图:

        

        从结构示意图我们可以看出以下区别:

           1>变长字段长度列表变成了-->字段长度偏移列表

           2>少了NULL值列表

      数据完整信息:

        

 

          区别:

            1>Redundant会把所有列都在字段长度偏移列表进行储存,包括隐藏列,当然顺序依然是逆序。

            2>Redundant采用偏移量也就是相邻两列的差值进行储存。

              第一列:row_id 六个字节  0x06
              第二列:transaction_id 六个字节 0x0c - 0x06 = 0x06
              第三列:roll_pointer  七个字节  0x13 - 0x0c = 0x07
              。。。。。。。

              以此类推我们就可以获取完整的储存信息

            3>我们在第二条数据可以看到,在真实数据的位置我们是对空值的列进行了相应的用00进行替代保存。在Compact行格式里面我们是不会进行保存的。

      记录头信息:

        预留位1  一:没有进行使用

        预留位2  一:没有进行使用

        delete_mask   一:是否被删除

        min_rec_mask  一:该记录是否为B+树中非叶子节点的最小记录

        n_owned  四: 当前嘈管理的记录数

        heap_no 十三:当前数据在记录堆的位置

        n_field    十: 表示记录中列的数量

        1byte_offs_flag  一:标记字段长度偏移列表中的偏移量是使用1字节还是2字节表示的

        next_record  十六:下一条记录的相对位置

      区别:

        1>少了record_type这个属性

        2>多了n_field1byte_offs_flag这两个属性
   行溢出数据:

     我们在前面提到过一个问题,那就是我们MySQL数据库是采用页作为磁盘和内存的中间交换,一页可以储存16k的数据,那么如果我们的一条数据超过了这个内存大小,又会发生什么样的情况呢?其实在这       里我觉得是没有必要关心多大的数据会发生行溢出的,如果有兴趣可以自行百度。在Compact行格式和Redundant中,对于这种特别大的数据的处理方式就是在真实数据的储存地方留下20个字节的内存用来       储存指向下一页的地址。意思就是用几页进行储存,这些页之间的联系是使用20个字节内存进行维护。

      

   Dynamic和Compressed:

      这两个行格式和Compact是非常相似的,它们的区别就在于对于上面提出的行溢出的处理。Dynamic是使用所有的真实数据储存空间进行储存其它页面的地址,把所有的真实数据都储存在其它页面中。

      

      相比于Dynamic来说,Compressed行格式的处理仅仅是加上了压缩算法进行压缩,节省空间。

   CHAR类型数据储存:

      我们在前面使用Compact行格式的提到过,比如我们的第一条数据的C3列因为是CHAR的数据类型,所以在变长数据长度列表里面是不进行储存的。但是在最后需要提出一点就是在那里我们采用的是定长的      字符集ASCII,但是如果我们把字符集换成UTF8的话这一列数据还是会在变长数据长度列表里面进行储存的。

      

 

posted @ 2018-04-16 14:14  GoNewLife  阅读(1983)  评论(0编辑  收藏  举报