MySQL(九)InnoDB行格式

2023-07-12,,

InnoDB格式

查看默认行格式:
select @@innodb_default_row_format;
查看数据库表使用的行格式
mysql> use atguigudb;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A Database changed
mysql> create table emp3 ( id int, name varchar(50) ) row_format=compact;
Query OK, 0 rows affected (0.02 sec) mysql> show table status like 'emp3'\G
*************************** 1. row ***************************
Name: emp3
Engine: InnoDB
Version: 10
Row_format: Compact
Rows: 0
Avg_row_length: 0
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: NULL
Create_time: 2023-04-03 00:27:36
Update_time: NULL
Check_time: NULL
Collation: utf8mb3_general_ci
Checksum: NULL
Create_options: row_format=COMPACT
Comment:
1 row in set (0.00 sec)
修改行格式
mysql> alter table emp3 row_format=dynamic;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0 mysql> show table status like 'emp3'\G
*************************** 1. row ***************************
Name: emp3
Engine: InnoDB
Version: 10
Row_format: Dynamic
Rows: 0
Avg_row_length: 0
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: NULL
Create_time: 2023-04-03 00:32:49
Update_time: NULL
Check_time: NULL
Collation: utf8mb3_general_ci
Checksum: NULL
Create_options: row_format=DYNAMIC
Comment:
1 row in set (0.00 sec)
compact行格式

变长字段长度列表:mysql中支持变长的数据类型,即变长字段中存储的字节数不是固定的,如VARCHAR、VARBINARY、TEXT、BLOB类型,但是在实际存储真实数据的时候需要记录数据占用的字节数,COMPACT行格式将变长字段占用的长度放在记录的开头部位,形成变长字段长度列表

字段的变长字段列表以及下面的存储都是倒序的,这是因为底层都是二进制,逆序正好是存放在低位

NULL值列表:Compact行格式会把表中可以为NULL的字段统一管理起来,存在这个标记为NULL值列表中,如果表中没有可以为NULL的字段,则NULL值列表也就不存在了

如有三个字段a、b、c,其中a是主键,存储a=0,b=null,c=2,则行格式中的NULL值列表会存储01,0代表c不为null(倒序所以c在前面),0代表b为null,NULL值列表会自动跳过主键和NOT NULL字段

记录头信息(5字节):前面讲了,见2.2

记录的真实数据:一条记录的真实记录部分除了我们自己定义的列的数据,还会有三个隐藏列:

row_id:行id,唯一标识一条记录
transaction_id:事务id
roll_pointer:回滚指针

row_id即是前面在介绍INNODB创建聚簇索引的时候,在没有主键和unique作为索引的情况下为每一列指定的一个自动主键

​ 下面创建一个表,来底层查看一下记录的二进制文件(开卷!)

​ 然后查看数据库表的十六进制显示的ibd文件:

03 02 01:对应记录的变长字段长度列表,即倒序为col4、col2、col1的实际存储字节,col3为定长,所以不记录
00:NULL值列表,表示全不为null
00 00 10 00 2c(正好五个字节):记录头信息
00 00 00 2b 68 00(6B):row_id
00 00 00 00 06 05(6B):trasaction_id
80 00 00 00 32 01 10(7B):roll_pointer
61:16进制的a
62 62: 16进制的bb
62 62 20 ... 20:定长字段bb,20表示为空

Dynamic与Compressed行格式
行溢出

​ 在创建表的时候,如使用varchar变长类型,按照类型大小应该能够设置varchar(65535),提示创建失败:[Err] 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

CREATE TABLE test (
`name` VARCHAR(65535)
)CHARSET=ASCII ROW_FORMAT=COMPACT;

使用ASCII编码的原因是一个字符占一个字节(变长类型的括号中的是字符),否则默认的表编码为utf8,则是65535个字符 = 65535 / 3 个字节

​ 而使用65532就能创建成功

CREATE TABLE test (
`name` VARCHAR(65532)
)CHARSET=ASCII ROW_FORMAT=COMPACT;

原因就在于行格式中,由于记录变长,所以变长字段长度列表会占用两个字节,NULL值列表会占用1个字节

​ 如果使用NOT NULL约束,则就能创建65533大小的表:

CREATE TABLE test (
`name` VARCHAR(65533) NOT NULL
)CHARSET=ASCII ROW_FORMAT=COMPACT;

行溢出:一个页的大小为16KB,即16384个字节,而上面一个字段就用去65535,这种一个页存放不下一条记录的现象,叫做行溢出

页的扩展:在Compact和Redundant行格式中,当出现占用空间特别大的列导致行溢出的时候,在记录真实的数据出只会存储一部分数据,而把剩余数据分散存储在其他几个页中进行分页存储,并使用20个字节存储指向这些地址(并且包含这些分散在其他页的数据所占的字节数),从而可以找到剩余数据所在的页。

Dynamic与Compressed行格式

在MySQL8.0中,默认的行格式就是Dynamic,Dynamic、Compressed行格式和Compact行格式基本相同,只不过在处理行溢出上有所差异,采用的是完全的行溢出方式即行溢出的字段完全不存放真实的数据,只存放20字节存储溢出页的地址。

​ 而Compressed行格式则是在Dynamic的基础上对存储在行之中的数据使用zlib算法进行了压缩,因此对于BLOB、TEXT、VARCHAR这种大长度类型的数据进行有效的存储。

Redundant行格式

​ Redundant行格式是MySQL5.0之前InnoDB的行记录存储方式,和Compact的主要区别在于使用了字段长度偏移列表,而没有变长字段长度列表NULL值列表

字段长度偏移列表:与变长长度列表主要有两处不同:

Redundant行格式会将该条记录的所有列(包含隐藏列)的长度按照逆序存储到字段长度偏移列表(记录了全部长度,自然也就不需要NULL值列表了)
使用的是相邻两个数值的差值来计算每个列值的长度

​ 除此之外还有头记录信息中的两个不同,这里就不写了 - -

MySQL(九)InnoDB行格式的相关教程结束。

《MySQL(九)InnoDB行格式.doc》

下载本文的Word格式文档,以方便收藏与打印。