1.行格式
1.1 Compact行格式
1.1.1 示意图
1.1.2 准备一下
1)建表
mysql> CREATE TABLE record_format_demo (
-> c1 VARCHAR(10),
-> c2 VARCHAR(10) NOT NULL,
-> c3 CHAR(10),
-> c4 VARCHAR(10)
-> ) CHARSET=ascii ROW_FORMAT=COMPACT;
Query OK, 0 rows affected (0.03 sec)
2)插入数据
mysql> INSERT INTO record_format_demo(c1, c2, c3, c4) VALUES('aaaa', 'bbb', 'cc', 'd'), ('eeee', 'fff', NULL,
NULL);
Query OK, 2 rows affected (0.02 sec)
Records: 2 Duplicates: 0 Warnings: 0
4)查看一下
mysql> SELECT * FROM record_format_demo;
+------+-----+------+------+
| c1 | c2 | c3 | c4 |
+------+-----+------+------+
| aaaa | bbb | cc | d |
| eeee | fff | NULL | NULL |
+------+-----+------+------+
2 rows inset (0.00 sec)
1.1.3 变长字段长度列表
我们知道Mysql支持一些变长的数据类型,比如VARCHAR(M)、各种TEXT类型,各种BLOG类型,我们也可以把拥有这些数据类型的列称为 变长字段,变长字段中存储多少字节的数据是不固定的,所以我们在存储真实数据的时候需要顺便把这些数据占用的字节也存起来。
1)INSERT INTO record_format_demo(c1, c2, c3, c4) VALUES (‘aaaa’, ‘bbb’, ‘cc’, ‘d’)
由于是ascii字符集,所以每个字符占一个字节,所以变长列(这里不包含cc,因为是char)每个长度为 04 03 01,另外非常重要的一点是:变长字段长度列表是逆序排列的,所以最终的的列表为 01 03 04。
用图来表示就是:
提出问题:当列中出现NULL时怎么存储那?往下看😘
2)INSERT INTO record_format_demo (c1, c2, c3, c4) VALUES (‘eeee’, ‘fff’, NULL,NULL)
1)上面的列都是非NULL的,如果出现NULL怎么存储那?**答案是:值为NULL的列是不存储的。**也就是说对于2)来说,c4列为NULL,所以第二条记录只需要存储c1和c2的列长度即可(c3是char,不是变长列)。
用图来表示就是:
1.1.4 NULL值列表
1)存放规则
- 是什么列都会算进去吗?:主键列、被NOT NULL修饰的列都是不可以存储NULL值的,所以在统计的时候不会把这些列算进去。⽐⽅说表record_format_demo的3个列 c1、c3、c4都是允许存储NULL值的,⽽c2列是被NOT NULL修饰,不允许存储NULL值。只统计NOT NULL的列
- 按照什么规则来统计 NOT NULL的列那?:1、用位来表示,1表示NULL,0表示NOT NULL; 2、逆序
2)举例说明
像上面的的表record_format_demo有3个值允许为NULL,所以这3个列和二进制的对应关系如下:
4)第一条记录怎么存
INSERT INTO record_format_demo(c1, c2, c3, c4) VALUES (‘aaaa’, ‘bbb’, ‘cc’, ‘d’),因为这条记录没有null值,所以存储之后长这个样:
5) 第二条记录怎么存
INSERT INTO record_format_demo (c1, c2, c3, c4) VALUES (‘eeee’, ‘fff’, NULL,NULL),由于这条记录中c3和c4都为NULL,所以这3个列对应的二进制的情况如下:
6)有个规则要说明一下
为什么上面两个图都展示的是8个位,因为总共就3个位,如果NOT NULL 超过8个位,那就要用2个字节表示。
7) 两条记录完整展示
1.1.5 记录头信息
1)说明
除了变⻓字段⻓度列表、NULL值列表之外,还有⼀个⽤于描述记录的记录头信息,它是由固定的5个字节组成。5个字节也就是40个⼆进制位。
2)图示
3)拿第一条记录图示说明
这个说明 head_no有值、next_record有值。
1.1.6 记录的真实数据
1)真实数据里还有“假数据”
对于record_format_demo来说,记录的真实数据除了c1、c2、c3、c4这⼏个我们⾃⼰定义的列的数据以外,MySQL会为每个记录默认的添加⼀些列(也称为隐藏列),具体的列如下:
**这里需要提一下InnoDB表对主键的生成策略:优先使用用户自定义的主键作为主键,如果没有就是用Unique键作为主键,如果都没有的话,InnoDB会为表默认生成一个名为row_id的隐藏列作为主键。**其余两个transaction_id、roll_pointer是一定有的,row_id是可选的。
2) 两条记录完整展示
注意以下几点:
- 由于record_format_demo没有定义主键,所以会生成row_id
- 表record_format_demo使⽤的是ascii字符集,所以0x61616161就表示字符串’aaaa’,0x626262就表示字符串’bbb’,以此类推
- **char的填充策略:**注意第1条记录中c3列的值,它是CHAR(10)类型的,它实际存储的字符串是:‘cc’,⽽ascii字符集中的字节表示是’0x6363’,虽然表示这个字符串只占⽤了 2个字节,但整个c3列仍然占⽤了10个字节的空间,除真实数据以外的8个字节的统统都⽤空格字符填充,空格字符在ascii字符集的表示就是0x20
- **有了NULL值列表,真实列就不需要存储了:**第2条记录中c3和c4列的值都为NULL,它们被存储在了前边的NULL值列表处,在记录的真实数据处就不再冗余存储,从⽽节省存储空间。
1.2 Redundant行格式
Redundant⾏格式是MySQL5.0之前⽤的⼀种⾏格式,也就是说它已经⾮常⽼ 了,如果想研究可以自己看小册。
1.3 Dynamic和Compressed行格式
下边要介绍另外两个⾏格式,Dynamic和Compressed⾏格式,我现在使⽤的MySQL版本是5.7,它的默认⾏格式就是Dynamic,这俩⾏格式和Compact⾏格式挺像, 只不过在处理⾏溢出数据时有点⼉分歧,它们不会在记录的真实数据处存储字段真实数据的前768个字节,⽽是把所有的字节都存储到其他⻚⾯中,只在记录的真 实数据处存储其他⻚⾯的地址,就像这样(可以理解为引用,768个字节如果换成200多个引用是不是更好拿):😨
2、总结
1)⻚是MySQL中磁盘和内存交互的基本单位,也是MySQL是管理存储空间的基本单位。
2)指定和修改⾏格式的语法如下:
CREATE TABLE 表名 (列的信息) ROW_FORMAT=⾏格式名称
ALTER TABLE 表名 ROW_FORMAT=⾏格式名称
3)InnoDB目前定义了4种行格式:
Compact:
Redundant:
Dynamic和Compressed⾏格式
这两种⾏格式类似于COMPACT⾏格式,只不过在处理⾏溢出数据时有点⼉分歧,它们不会在记录的真实数据处存储字符串的前768个字节,⽽是把所有的 字节都存储到其他⻚⾯中,只在记录的真实数据处存储其他⻚⾯的地址。 另外,Compressed⾏格式会采⽤压缩算法对⻚⾯进⾏压缩。