文章目录
- InnoDB - 行格式
- 1. 什么是行格式
- 2. 四种行格式
- 3. Compact行格式
InnoDB - 行格式
1. 什么是行格式
我们平时是以行记录为单位向表中插入数据的,这些数据在磁盘上的存放方式被称为行格式或者记录格式。
InnoDB引擎中支持四种行格式:Compact、Redundant、Dynamic、Compressed
可以在创建表的时候指定行格式,或者直接使用alter命令更改表的行格式。
-
创建表的时候指定行格式
CREATE TABLE 表名 ( ) row_format = 行格式名称;
-
更改表的时候指定行格式
ALTER TABLE 表名 ROW_FORMAT = 行格式名称;
2. 四种行格式
如上所述:Compact、Redundant、Dynamic、Compressed
行格式给我们的数据添加了很多额外的字段,这些字段记录了本条数据的一下信息,这些信息属于是MySQL服务器为了描述这条记录(行数据)而不得不额外添加的一些信息。
这几种行格式大同小异,都是在你的表的基础上给你增加几个隐形的字段,目的是为了加快MySQL的运行效率。
本篇文章只描述一下Compact行格式。
3. Compact行格式
Compact行格式给表增加了三个额外字段:变长字段长度列表、NULL值列表、记录头信息。
- 变长字段长度列表:你的有些字段的值的长度是不确定的,例如varchar()、bolg、text这些类型,数据的长度不固定,但是MySQL解析的时候又不想猜你有几个字节,所以就使用这个列表记录所有会变化的字段的长度。
- NULL值列表:有的字段的值是可以为空的,这些数据是不需要解析处理的,所以MySQL会将这些字段记录下来。(主键和not null 关键字修饰的字段不能为空,所以不会被记录)
- 记录头信息:有很多字段组成,不同字段有不同的作用,主要有:标记该记录是否被删除、标记该记录是否是B+树叶子节点、该记录在记录堆中的位置信息…
这三个字段是MySQL提供给自己使用的。现在详细看看它们。
-
变长字段的长度列表
如名字所示,你的表中有多少字段的值的长度是可变的,它就记录这些可变的数据的长度。
我们知道MySQL中支持一些不定长的数据类型:varchar、blog、text、longtext…我们可以将这些数据类型的列称为变长字段,变长字段中存储多长字节的数据是不固定的,所以MySQL将这些数据存储时顺便存上它们的长度,这样就可以更快的解析处理了。
在compact行格式中,把所有变长字段的真实数据占用的字节长度都存放在记录的开头位置,从而形成一个长度列表,称为变长字段的长度列表,各个变长字段数据占用的字节数按照列的顺序逆序存放。强调一下,逆序存放。
假如现在有三个字段:id、name、password,其中id是int类型,所以它不是变长字段,name和password都是varchar类型,它们是变长字段,所以长度列表中会记录他俩的长度。
name: xiaoming password: 123
如上,name的长度是8个字节,十六进制是0x08;password是3个字节,十六进制是0x03。
存储在列表中就是:0308。
放在整个行中就是:
但是还有一个问题:如果某个字段存储的数据特别多,你只用一个字节可以存吗?或者说:你怎么知道03代表长度还是0308代表长度呢?
放心 ,InnoDB 有它的一套规则。这里就不展开讲述了。
另外需要注意的是:变长字段长度列表中只存储非NULL的列内容占用的长度,那肯定啊,为NULL的值你记录它干啥?
同时,这个列表的中的字段不仅仅会被变长字段影响,还会被MySQL所使用字符集影响:
对于 CHAR() 类型的列来说,当列采用的是定长字符集时,该列占用的字节数不会被加到变长字段长度列表,而如果采用变长字符集时,该列占用的字节数也会被加到变长字段长度列表。
-
NULL值列表
某些表中的某些列可能存储NULL值,MySQL会将这些值为NULL的列统一管理起来,存储到NULl值列表中。
首先,主键和被not null 修饰的字段不会被存储。其次,如果此行的数据没有NULL值,这个NULL值列表也就没有意义了。
否则,每一个允许存储NULL值的字段对应一个二进制位,二进制位按照字段的顺序逆序排序,强调:逆序。
二进制位的意义:
- 二进制位的值为1:该字段的值为NULL。
- 二进制位的值为0:该字段的值不为NULL。
如下:
但是MySQL规定NULL值列表必须使用整数个字节的位表示,即:8、16、32…
并且,对于这一行数据来说,值为NULL的字段是不被存储的。
所以上面那张图完善一下其实是这样:
-
记录头信息
这个字段固定有5个字节,即40个二进制位,不同的位代表不同的意思,如下:
名称 | 大小(bit) | 作用 |
---|---|---|
预留位 | 2 | 待使用 |
delete_mask | 1 | 该记录是否被删除 |
min_rec_mask | 1 | B+树的每层非叶子节点中的最小记录都会添加该标记 |
n_owned | 4 | 表示当前记录拥有的记录数 |
heap_no | 13 | 表示当前记录在页中的位置 |
record_type | 3 | 表示当前记录的类型0:普通记录1:表示B+树非叶子节点记录2:表示最小记录3:表示最大记录 |
next_record | 16 | 表示下一条记录的相对位置 |
看到delete_mask大家可能会有些疑惑:这个标志不是“该条记录是否被删除”吗?我们删除一条数据之后MySQL原来并没有真正的删除它?对,MySQL执行的也是逻辑删除,至于具体是怎样做的,就在数据具体的存储方式:InnoDB - 页结构 中与其他头信息一起说吧~。
-
隐藏字段
背过MySQL面试题的大概都知道,在创建表的时候MySQL提供了几个隐藏字段(实现MVCC机制的三个隐藏字段)
- row_id:行id,唯一标识
- transaction_id:操作此行数据的事务的id
- roll_pointer:回滚指针
大家可能都背过,这里就不展开讲了。于是我们创建的表,加上所有隐藏字段之后其实是这样的:
综上所述就是MySQL的Compact行格式。