1.前言
在mysql中我们在插入数据的时候主要是以记录为单位向表中插入数据的,这些记录在磁盘中存放的形式也被称为行格式或者记录格式,innodb存储引擎设计的行格式主要有如下4种:1)compact 2)redundant 3)dynamic 4)compressed
2.指定行格式的语法
create table 表名(列信息) row_format=行格式名称 alter table 表名 row_format=行格式命令
3.compact
变长字段长度列表 | NULL值列表 | 记录头信息 | 列1的值 | 列2的值 | ...... | 列n的值 |
其中,上面的内容可以分为两个部分,前三个方框的内容可以被概括为记录的额外信息,后面的被称为记录的真实数据
记录的额外信息:
1) 变长字段长度列表
我们都了解mysql支持一些变长的数据类型,比如varchar(M)varibinary(M) 各种TEXT类型,各种BLOB类型。我们可以把这些数据类型的列称为变长字段。变长字段中存储多少字节的数据是不固定的,所以我们在存储真实数据库的时候需要顺便把这些数据占用的字节数也存起来,这样才不至于把mysql服务器搞懵逼。也就是说这些变长字段占用的存储空间分为两部分:
- 真正的数据内容
- 该数据占用的字节数
在compact行格式中,所有变长字段的真实数据占用的字节数都存放在记录的开头位置,从而形成一个变长字段长度列表,各变长字段的真实数据占用的字节数按照列的顺序逆序存放,比如说如下的某张表的记录,假设各个列采用的都是ascii字符集,每个字符只需要一个字节来编码,来看一下第一条记录各变长字段内容的长度。
列名 | 存储内容 | 内容长度(十进制) | 内容长度(十六进制) |
c1 | 'aaaa' | 4 | 0x04 |
c2 | 'bbb' | 3 | 0x03 |
c3 | 'd' | 1 | 0x01 |
因为这些长度值需要按照列的顺序的逆序存放,所以最后变长字段长度列表的字节串用十六进制表示的效果是: 01 03 04 因此,第一条记录存放的形式就如下图所示了:
01 03 04 | Null值列表 | 记录头信息 | 列值1的值 | 列值2的值 | ... | 列值n的值 |
innodb在读取记录的变长字段长度列表时先查看表结构,如果某个变长字段允许存储的最大字节数不大于255,可以认为使用1字节来表示真实数据占用的字节数。
2)Null值列表
我们知道,一条记录中的某些列值可能存储NULL值,如果把这些Null值都放在记录的真实数据中存储会很占地方,所以compact行格式把一条记录中值为NULL的列统一管理起来,存储到NULL值列表中
1.首先会统计表中允许存储NULL的列有哪些。主键列以及使用NOT NULL修饰的列都是不可以存储NULL值的,所以在统计时不会把这些列算进去
2.如果表中没有允许存储NULL的列,则NULL值列表也就不存在了,否则将每个允许存储NULL的列对应一个二进制位,二进制位按照列的顺序逆序排序,当二进制位为1时,代表该列的值为NULL,当二进制位为0时,代表该列的值不为NULL
3)记录头信息
除了变长字段长度列表、NULL值列表之外,还有一个称之为记录头信息的部分。记录头信息由固定的5字节组成,用于描述记录的一些属性。
预留位1 | 预留位2 | deleted_flag | min_rec_flag | n_owned | heap_no | record_type | next_record |
这里就介绍几个比较重要的信息:
1.delete_flag:标记该记录是否被删除
2.heap_no:表示当前记录在页面堆中的相对位置
3.record_type:表示当前记录的类型,0表示普通记录,1表示B+树非叶子节点的目录向记录,2表示infimum记录,3表示Supremum记录
4.next_recore:表示下一条记录的相对位置
记录的真实数据
对于一个普通表来说,记录的真实数据除了c1、c2、c3、c4这几个我们自己定义的列数据之外,Mysql会为每个记录默认添加一些列(隐藏列),具体如下表:
列名 | 是否必须 | 占用空间 | 描述 |
row_id | 否 | 6字节 | 行id,唯一标识一条记录 |
trx_id | 是 | 6字节 | 事务id |
roll_pointer | 是 | 7字节 | 回滚指针 |
实际上几个列的真正名称是DB_ROW_ID,DB_TRX_ID,DB_ROLL_PTR
实际上innodb表的主键生成策略:优先使用用户自定义的主键作为主键,如果用户没有定义主键,则选取一个不允许存储NULL值的unque键作为主键,如果表中连不允许存储NULL值的unque键都没有定义,则innodb会为表默认添加一个名为row_id的隐藏列作为主键
4.总结:
页是innodb中磁盘和内存交互的基本单位,也是innodb管理存储空间的基本单位,默认大小为16KB
指定和修改行格式的语法如下:
create table 表名(列的信息) row_format=行格式名称
alter table 表名 Row_Format=行格式名称
4.1 compact格式,如下图
变长字段长度列表 | Null值列表 | 记录头信息 | 列1的值 | 列2的值 | xxx | 列n的值 |
4.2 REDUNDANT行格式,如下图
字段长度偏移量 | 记录头信息 | 列1的值 | 列2的值 | xxx | 列你的值 |
4.3 dynamic和compressed行格式
这两种行格式类似于compact行格式,只不过在处理溢出列数据时有点分歧,它们不会在记录的真实数据处存储列真实数据的前768字节,而是把所有的数据都存储都所谓的溢出页中,只在记录的真实数据处存储指向这些溢出页的地址。另外,compressed行格式会采用压缩算法对页面进行压缩。
我发现截止目前(5.7.30-log)版本默认的行格式是 innodb_default_row_format | dynamic ,另外redundant行格式已经不用了
然后说说溢出列:就是说如果某一列中的数据非常多,则在本记录的真实数据处只会存储该列前768字节的数据以及一个指向其他页的地址,然后把剩下的数据存储到其它页中。这些存储768字节之外的数据的页面也称之为溢出页。