Mysql深度讲解InnoDB引擎与Index索引(一)

前言

笔者相信大多数同学都清楚Mysql的索引(Index)对查找数据的速度提升是有很大帮助的,了解的更深入的一些的同学可能也知道Mysql的索引模型是B+树。但是笔者发现网上对于这些知识非常的琐碎,不利于新入门的同学理解Mysql 索引底层的运作机制。本篇博客就是要从InnoDB开始一步一步的推导到Index的原理,当然这些都是笔者个人的理解和学到的内容,如果有错误的地方,欢迎大家指正,互相进步。更多Mysql调优内容请点击【Mysql优化-深度讲解系列目录】

InnoDB数据加载的原理

相信大家都明白数据永远会存在磁盘上,但是在处理数据的时候并不是在磁盘上处理的。首先要把数据加载到内存中,然后再由CPU进行计算。笔者相信凡是学过计算机组成原理的同学应该都有印象,数据加载并不是需要哪个bit就去加载哪个bit,而是按照内存分页的大小一起把相邻的数据加载到一个内存页里,来减少IO的消耗。在InnoDB中也是一样,但是它有自己的加载规则。InnoDB也是把数据分成若干个页面,以页为基本单位进行内存和磁盘间交互。InnoDB系统设定的内存页大小为16KB,也就是说每次交互都会从磁盘上读取16KB的数据到内存中处理,同样反过来每次写入磁盘的时候也是按照16KB的大小写入的。

InnoDB数据页(Page)大小

既然上面已经说了InnoDB的默认内存页是16KB,自然不是信口胡来的,其实是有命令可查的这个命令就是SHOW GLOBAL STATUS,这个命令可以把Mysql中所有的全局变量以表格的形式显示出来,所以我们要找InnoDB的页大小就可以使用这个命令。

SHOW GLOBAL STATUS like 'Innodb_page_size';
Variable_nameValue
Innodb_page_size16384

可以看到显示的值是16384=1024*16,也就是我们说的16KB。

InnoDB数据页结构

InnoDB数据页结构如下图。
在这里插入图片描述
其各个部分的作用如下表:

字段名大小作用中文名
File Header38 Byte存放页的一些通用信息文件头
Page Header56 Byte存放数据页专有的一些信息页头
Infimum + Supremum26 Byte存放两个虚拟的行记录数据下界限和上界界限
User RecordsIndetermination实际存储的行记录内容,大小不确定用户记录
Free SpaceIndetermination页中尚未使用的空间,大小不确定空闲空间
Page DirectoryIndetermination页中的某些记录的相对位置,大小不确定页目录
File Trailer8 Byte校验页是否完整,如果数据超过一页,此项将会指向下一页地址文件指针

InnoDB行格式(Row Format)

说完数据页,就轮到了在User Records里面存的行了。那么一行数据到底在MySQL底层是如何存储的呢?在InnoDB中,一行数据可以有不同的策略去存,一般来说大概有4种分别是Compact、Redundant、Dynamic和Compressed四种行格式。其中Compact,Dynamic和Compressed三种存储格式基本一样,只不过在处理行溢出数据时有所区别。Dynamic不会在记录的真实数据处存储一部分数据,而是把所有的数据都存储到其他页面中,只在记录的真实数据处存储其他页面的地址。Compressed行格式会采用压缩算法对页面进行压缩。目前的版本里如果不指定行格式,默认会使用Dynamic。因此我们只要详细的说下Compact的存储格式,后面两个也就一起解释了。

Compact行格式

在这里插入图片描述
上图就是Compact行格式的大概样子。前三个部分(变长字段长度列表,NULL值列表,记录头信息)称为记录额外信息的部分。这部分是为了表述这条记录不得不添加的一些额外信息。

变长字段长度列表

Mysql是支持变长数据类型的,最常用的VARCHAR(M)、VARBINARY(M)、TEXT、BLOB等等类型。其存储的数据子节是不固定的,相信这些知识大家都有所耳闻。为了存储这些变长类型,Mysql在存储的时候也会把这些数据占用的字节数也存起来。在Compact格式中,会把所有属于变长字段的真实数据所占用的字节长度都放在本行的头部,如果有多个变长类型字段就会形成一个变长字段长度列表。注:CHAR是固定长度的类型,VARCHAR则是可变长度的类型,比如VARCHAR(M)种M代表最大能存多少个字符。但是这个里面存得列是按照顺序逆序放置的。如果表里没有一个字段是变长类型的,那么这部分就不会存在了。

NULL值列表

数据在存储的时候有些内容会是空值,也就是说NULL。那么这些字段也会在Compact格式里统一管理起来。值得一提的是,如果所有的字段都用NOT NULL标识了,那么NULL值列表这部分也不会存在。NULL值列表使用二进制进行null值标识:1代表该值为null,0代表改制不为null。比如11001表示,该行第一、第二、第五个字段为null,第三、第四两个字段不为null。

记录头信息

头信息是由固定的5个字节组成,一共形成了40个二进制位,不同的位代表不同的含义。

列名位数(总40位)说明
空位11未知作用,可能是预留功能
空位21未知作用,可能是预留功能
delete_mask1删除标记,标识是否被删除了
min_rec_mask1B+树的每层非叶子节点中的最小记录都会添加该标记
n_owned4表示当前记录拥有的记录数
heap_no13表示当前记录在记录堆的位置信息
record_type3表示当前记录的类型,0表示普通记录,1表示B+树非叶子节点 记录,2表示最小记录,3表示最大记录
next_record16表示下一条记录的相对位置
数据列

数据列是标识字段个数以及真实信息的部分,唯一要说的就是除了用户自定义的字段以外,还有三个隐藏列。

列名强制说明大小
row_id行id,当没有指定主键的时候,作为默认主键存在,自增6 Byte
transaction_id事务id6 Byte
roll_pointer回滚指针7 Byte

Redundant行格式

Redundant行格式是MySQL 5.0版本之前使用的格式,目前还在支持主要是为了向前兼容,目前已经很少使用,就简单介绍一下。
在这里插入图片描述
Redundant的存储格式为:第一部分是字段长度偏移列表,同样是按照列的顺序逆序放置的。当列的长度小于255 Byte,用1 Byte表示;若大于255 Byte,用2 Byte表示。第二个部分是记录头信息,长度为6 Byte。最后的部分就是实际存储的每个列的数据了。

InnoDB数据溢出

先举一个数据溢出例子,VARCHAR类型最多可以使用65535个Byte。那么VARCHAR能够使用65535这个数字作为长度吗?答案是不可以。比如想要在表里声明一个字段sample_field长度为65535,则直接会报错。

CREATE TABLE test_demo(
sample_field VARCHAR(65535)
)CHARSET=ascii ROW_FORMAT=dynamic; 

Error Code: 1118. Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs

可以看到报错的内容为Row size too large,说明Mysql认为这一行的内容太大了。也就是说Mysql限制每一行都必须小于65535,除非有BLOBs类型的数据,因为不算在内(not counting BLOBs)。那么VARCHAR(65535)后面的数字代表的是什么呢?其实就是真实的数据存的内容。还记得上面的内容,还有变长,NULL值列表,头信息的部分。刚才的例子中,创建的字段是变长且允许为NULL的因此这两部分是必须有的,直接写65535就挤压了这部分的空间,因此会报错。那么给他们腾出这部分空间就可以了,比如换成65532就可以顺利执行了。

行溢出

但是这样就有一个问题了:在博客最初说到InnoDB一页只有16K=16384 Byte,现在我一行就有65532 Byte。很明显一页都无法完全存储一行数据,那么一行数据就需要用多个页去存储,这就是所谓的行溢出。那么这个怎么处理呢?Compact格式的处理方式是在一行存储真实数据最后的部分存入一个指针,指向下一个页地址,做了一个链式的存储。Compressed上面已经说了会采用压缩算法对页面进行压缩。Dynamic则是在第一页存储的时候不会存储真实的数据,只会存地址。那么真实的数据就会存到这些地址指向的页里面。说到了Dynamic处理行溢出的方式,是不是有点索引的感觉了。

总结

本篇博客对Mysql的InnoDB的结构进行了一个比较详细的说明,希望通过这些内容可以增加读者对InnoDB引擎存储数据的理解。之所以对这些进行一个详细的说明,就是为了更好引出索引的概念。下一篇【Mysql深度讲解InnoDB引擎与Index索引(二)】就会从零开始讲解InnoDB中的index底层是如何实现的。

Dynamic处理行溢出:
在这里插入图片描述

Compact处理行溢出:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值