-
准备工作
- 表中的数据到底存到了哪里?
- 表中的数据以什么格式存放
- mysql以什么方式来访问这些数据
-
Innodb页面简介
- Innodb是一个将表中的数据存放到磁盘上的存储引擎,即使我们关闭并重启服务器,数据库还是存在。
- 而真正处理数据的过程发生在内存中,所以需要将磁盘中的数据加载到内存中。
- 如果处理写或者修改的请求,还需要将内存中的内存刷新到磁盘中。
- Innodb采取的方式是,将数据划分为若干个页,以页作为磁盘和内存之间交互的基本单位,Innodb中页的大小一般为16K,也就是在一般情况下,一次最少从磁盘中读取16k的内容到内存中,一次最少把内存中的16k内容刷新到磁盘中。
系统变量innodb_page_size表面了Innodb存储引擎中的页大小,默认值为16384字节也就是16k,该变量只能在第一次初始化mysql数据目录时指定,之后再也不能更改了
-
Innodb行格式
我们平时都是以记录为单位向表中插入数据,这些记录在磁盘上的存放形式也被称为行格式或者记录格式。
Innodb存储引擎有4种不同类型的行格式:
- Compact(袖珍的)
- redundant(多余的)
- dynamic(动态的)
- compressed(压缩的)
-
指定行格式语法
-
Compact行格式
-
记录的额外信息
-
变长字段长度列表
- mysql存在一些变长的数据库类型,比如varchar、各种text,我们可以把拥有这些数据类型的列称为变长字段,变长字段中存储多少字节的数据是不固定的,我们存储真实的数据的时候需要顺便把这些数据占用的字节也存起来
- 所有字段的真实数据占用字节数都存放在记录开头位置,从而形成一个变长字段长度列表,各变长字段的真数据占用字节数按照列的顺序逆序存放。
-
Innodb在读取记录的变长字段长度列表时先查看表结构,如果某个变长字段允许存储的最大字节数小于255,可以认为只使用1个字节来表示真实的数据占用的字节数。
-
NULL值列表
-
一条记录中某些列可能存储null值,如果把这些null值都放到记录的真实数据中存储会很占地方,所以compact行格式把一条记录中值为null列统一管理起来,存放null值列表中,他们处理过程如下所示:
-
统计表中允许为null的列有哪些
-
如果表中允许存储null的列,则null值列表就不存在了,否则将每个允许存储null的列对应一个二进制位,二进制位按照列的顺序逆序排序,二进制位表示的意义如下:
- 二进制位的值为1时,代表该列的值为null
- 二进制位的值为0时,代表该列的值不为null
-
-
-
记录头信息
- 预留位1
- 预留位2
- deleted_flag:标记该记录是否被删除
- min_rec_flag: B+树的每层非叶子节点中最小的目录项记录都会添加该
- n_owned:一个页面中记录会被分成若干个组,每个组中有一个记录是带头大哥
- heap_no:表示当前记录在页面中的相对位置
- record_type: 标记当前记录的类型,0表示普通记录,1 表示B+树非叶子节点的目录项记录 2 表示infimum记录,3表示supermum记录
- next_record:下一条记录的相对位置
-
记录的真实信息
-
mysql会为每条记录默认添加一些列
- row_id: 6个字节 行id。唯一标记一条记录
- trx_id: 6个字节 事务id
- roll_pointer:7个字节 回滚指针
-
innodb的主键生产策略
- 优先使用用户自定义的主键为主键,如果用户没有定义主键,则选取一个不允许为空的unique键为主键,如果表中连不允许存在null的unique键都没有定义,则innodb会为表默认添加一个名为row_id为隐藏列作为主键。
-
CHAR列的存储的格式
- 在compact行格式下,变长字段长度列表只是用来存放一条记录中各个变长字段的值占用的字节长度的
-
Redundant行格式
- mysql5.0之前使用的一种格式,很古老了
-
字段长度偏移列表
-
Compact行格式的开头是变长字段长度列表,而redundant的行格式的开头是字段长度偏移列表,他与变长字段长度列表相比有两处不同:
- 没有了变长的两个字,意味着redundant行格式会把该条记录中所有列(包括隐藏列)的长度信息都按照逆序的存储到字段长度偏移列表
- 多个偏移两个字,这以为这计算列值长度的方式不像compact行格式那么直观,它是采用两个相邻偏移量的差值来计算各个列值的长度
-
按照两个相邻偏移量的差值来计算各个列值长度的意思就是
- 第一列 row_id 的长度就是0x06 个字节,也就是6个字节
- 第二列 trx_id 的长度就是0x06 个字节,也就是6个字节
- 第三列 roller_poiner 的长度就是0x0C--0x06 个字节,也就是7个字节
- 第四列 c1 的长度就是0x13 --0x0C个字节,也就是4个字节
- 第五列 c2 的长度就是0x1A --0x17 个字节,也就是3个字节
- 第六列 c3 的长度就是0x24 --0x1A 个字节,也就是10个字节
- 第七列 c4 的长度就是0x25 --0x24 个字节,也就是1个字节
-
记录头信息
- 记录头信息只占用6个字节,总计48个二进制位
-
记录头信息中的1Byte_offs_flag的值是怎么选择的
-
Redundant行格式的Null值的处理
-
Char列的存储格式
-
溢出列
-
溢出列
- 我们的记录会被存储到某个页面上来存储,而一个页的大小一般是16kb,也就是16384个字节,再compact和redundant行格式中,对于占用存储空间非常多的列,在记录的真实数据处只会存储该列的一部分数据,而把剩余的数据分散存储在几个其他的页中,然后在记录的真实数据处用20个字节执行这些页的地址。
- text、blog这些类型的列在存储的数据相当多的时候也成为溢出列。
-
产生溢出页的临界点
- 一个列在存储了多少字节之后会变为溢出列呢
-
Dynamic行格式和compressed行格式
- dynamic行格式和compressed行格式这两个行格式与compact行格式挺像的,只不过在处理溢出列时候有些不同,它们不会在记录真实数据处存储该溢出列真实数据的前768字节,而是把该列的所有真实数据都存储在溢出页面中,只在记录的真实数据处存储20 字节大小的指向溢出页的地址
- compressed行格式不同dynamic行格式一点是,compressed行格式采用压缩算法对页面进行压缩,以节省空间
-
总结
-
页是innodb中磁盘和内存交互的基本单位,也是innodb管理内存空间的基本单位,默认是16kb
-
innodb目前定义了4种行格式
- Compact
- Redundant
- Dynamic
- Compressed