在开文我先说明一下,接下来的数据库知识文章都是在微信公众号“咱们都是小青蛙”学习而后在经过本身的理解进行书写的。有兴趣的朋友能够去关注这个微信公众号。话很少说,咱们在平常使用数据库进行数据持 久化的时候有没有想过咱们的数据在数据库中是什么样的储存结构,咱们可能想的最多的是怎样进行SQL的调优,可是对于数据库都不熟悉能作到调优设计么?答案显然是不能!!因此咱们在这里开始数据库的第一 篇文章。数据库的记录储存结构。算法
咱们可能有不少熟悉的数据库储存引擎,好比说Inoodb,MyISAM,Memory。每一种储存引擎对于数据的持久化多是不一样的,好比说咱们的Memory储存引擎的数据都是不会写进磁盘的,全部的数据是保存在内存 中的,也就意味着若是咱们的服务器进行重启之后,数据是不会被进行保存的。固然,由于MySQL数据库默认的储存引擎是使用的Inoodb,因此咱们在这里是须要重点介绍这个储存引擎的。数据库
简介:服务器
Inoodb储存引擎是把数据储存在磁盘里面的储存引擎,它在内存和磁盘的交互中使用的是页这个数据单位。咱们都知道一个事情就是咱们在对磁盘进行访问的时候速度是很是慢的,因此咱们确定是不能接受一 条数据一条数据的进行取用。全部数据划分为若干页,一个数据页是能够保存16kb的数据,也就是说咱们每次在进行数据访问的时候是一次性的16kb数据。微信
行格式:学习
知道了数据库中咱们数据的大概储存方式,那么接下来咱们须要作的就是学习一条数据在咱们的数据库中是什么样的一个结构存在。咱们把数据库储存数据的格式称之为行格式或者是记录格式,咱们如今所使用 的行格式有Compact,Redundant,Dynamic,Compressed。固然随着时间的迁移咱们是会有更多的行格式出现。编码
Compact:spa
建立语法:咱们会在bysj数据库中建立一个表,test,方便咱们接下来对于储存结构的演示。以下所示,设置行格式咱们直接使用ROW_FORMAT=行格式名称 。咱们同时也对编码格式进行了设置为ASCII,这个 编码格式只能是储存空格,字母,标点符号,不可见字符,数字。因此汉字是不能够储存进来的!设计
接下来咱们插入两条数据:3d
结构示意图:以下图所示咱们能够看到的是分为两个大部分,第一部分就是记录额外信息,第二部分就是记录真实数据,接下来咱们对这两个部分进行详细的描述:指针
变长字段长度列表:
这个部分记录的是可变长字段的信息,好比说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_field
和1byte_offs_flag
这两个属性
行溢出数据:
咱们在前面提到过一个问题,那就是咱们MySQL数据库是采用页做为磁盘和内存的中间交换,一页能够储存16k的数据,那么若是咱们的一条数据超过了这个内存大小,又会发生什么样的状况呢?其实在这 里我以为是没有必要关心多大的数据会发生行溢出的,若是有兴趣能够自行百度。在Compact行格式和Redundant中,对于这种特别大的数据的处理方式就是在真实数据的储存地方留下20个字节的内存用来 储存指向下一页的地址。意思就是用几页进行储存,这些页之间的联系是使用20个字节内存进行维护。
Dynamic和Compressed:
这两个行格式和Compact是很是类似的,它们的区别就在于对于上面提出的行溢出的处理。Dynamic是使用全部的真实数据储存空间进行储存其它页面的地址,把全部的真实数据都储存在其它页面中。
相比于Dynamic来讲,Compressed行格式的处理仅仅是加上了压缩算法进行压缩,节省空间。
CHAR类型数据储存:
咱们在前面使用Compact行格式的提到过,好比咱们的第一条数据的C3列由于是CHAR的数据类型,因此在变长数据长度列表里面是不进行储存的。可是在最后须要提出一点就是在那里咱们采用的是定长的 字符集ASCII,可是若是咱们把字符集换成UTF8的话这一列数据仍是会在变长数据长度列表里面进行储存的。