InnoDB存储引擎行溢出和溢出页
我们应该知道Mysql中内存和磁盘之间的数据交互并不是以记录行为单位而是以页为单位,因为内存和磁盘间的处理速度差了几个数量级,单次读取一条记录那么Mysql无法高效运行,所以Mysql都是以页为基本单位管理存储空间的,我们的记录都会被分配到某个页中存储,一个页的大小一般为16kb,那么可以存储多少字节的数据呢?
16kb = 16*1024 = 16384字节
我们上章聊过,当一个varchar类型在字符集为ascii下最大可以存储的字节长度为65532,具体计算可以参考InnoDB行格式(3)VARCHAR最多能存储的数据
也就是说一个数据页无法放下,那么Mysql如何存储呢?
测试步骤
### 创建测试表,指定varchar最大字符长度
mysql> CREATE TABLE test_varchar_size(
-> c VARCHAR(65532)
-> ) CHARSET=ascii ROW_FORMAT=Compact;
Query OK, 0 rows affected (0.00 sec)
### 插入一条数据,字段c的值是采用REPEAT系统函数将a重复65532次得出的值
mysql> INSERT INTO test_varchar_size(c) VALUES(REPEAT('a', 65532));
Query OK, 1 row affected (0.00 sec)
得到测试表test_varchar_size的ibd文件,将其采用hexdump命令将其转换为16进制格式查看,具体操作参考
0000c070 73 75 70 72 65 6d 75 6d 14 c3 00 00 00 10 ff f0 |supremum........|
0000c080 00 00 00 00 02 04 00 00 00 00 8f 3e ae 00 00 01 |...........>....|
0000c090 22 01 10 61 61 61 61 61 61 61 61 61 61 61 61 61 |"..aaaaaaaaaaaaa|
0000c0a0 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 |aaaaaaaaaaaaaaaa|
......省略 45行都是61的
0000c380 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 |aaaaaaaaaaaaaaaa|
0000c390 61 61 61 00 00 00 66 00 00 00 04 00 00 00 26 00 |aaa...f.......&.|
Compact和Redundant行格式
从上面可以看出,一条记录中字符a仅仅占用768个字节,那么剩余的字符都去哪里了呢?这就和行格式有关,Compact和Redundant行格式中,对于占用空间非常大的列,在记录的真实数据存储空间只会存储一部分内容,剩余真实数据将分为几个页存储,记录真实数据的空间还会花费20个字节存储指向其它页的地址,所以页记录结构应该如下所示
上面这种一个数据页存储不下,真实数据只存储768个字节真实数据以及20个字节指向其它数据页的地址,剩余真实数据存储到其它数据页的这个过程称为行溢出,而存储超过768个字节的真实数据的数据页被称为溢出页。
Dynamic和Compressed行格式
这两种格式的行溢出存储格式稍有不同,这两个格式并不会在存储真实数据区域存储768个真实数据,而是将真实数据全部存储到其它数据页,只在真实数据处存储其它数据页的地址,如下所示