如果我们定义一个表,表中只有一个 VARCHAR 字段,如下:
CREATE TABLE test_varchar( c VARCHAR(60000) )
然后往这个字段插入 60000 个字符,会发生什么?
前边说过,MySQL 中磁盘和内存交互的基本单位是页,也就是说 MySQL 是以页为基本单位来管理存储空间的,我们的记录都会被分配到某个页中存储。而一个页的大小一般是 16KB,也就是 16384 字节,而一个 VARCHAR(M)类型的列就最多可以存储 65532 个字节,这样就可能造成一个页存放不了一条记录的情况。
在 Compact 和 Redundant 行格式中,对于占用存储空间非常大的列,在记录**的真实数据处只会存储该列的该列的前 768 个字节的数据,然后把剩余的数据分散存储在几个其他的页中,记录的真实数据处用 20 **个字节存储指向这些页的地址。这个过程也叫做行溢出,存储超出 768 字节的那些页面也被称为溢出页。
Dynamic 和 Compressed 行格式,不会在记录的真实数据处存储字段真实数据的前 768 个字节,而是把所有的字节都存储到其他页面中,只在记录的真实数据处存储其他页面的地址。
那发生行溢出的临界点是什么呢?也就是说在列存储多少字节的数据时就会发生行溢出?
MySQL **中规定一个页中至少存放两行记录**,以上边的 test_varchar 表为例, 它只有一个列 c,我们往这个表中插入两条记录,每条记录最少插入多少字节的数据才会行溢出的现象呢?这得分析一下页中的空间都是如何利用的。
每个页除了存放我们的记录以外,也需要存储一些页本身的信息,加起来需要 132 个字节的空间,其他的空间都可以被用来存储记录。每个记录需要的额外信息是 27 字节。
假设一个列中存储的数据字节数为 n,MySQL 规定如果该列不发生溢出的现象,就需要满足下边这个式子:
132 + 2×(27 + n) < 16384
求解这个式子得出的解是:n < 8099。也就是说如果一个列中存储的数据小于 8099 个字节,那么该列就不会成为溢出列,否则该列就需要成为溢出列。不过这个 8099 个字节的结论只是针对只有一个列的 test_varchar 表来说的,如果表中有多个列,那上边的式子和结论都需要改。所以重点就是:这个临界点具体值无关紧要,只要知道如果我们一条记录的某个列中存储的数据占用的字节数非常多时,该列就可能成为溢出列。