mysql变长类型字段varchar值更新变长或变短底层文件存储原理


为了搞清楚MySQL对于可变长度字段值修改时,如何高效操作数据文件的机制。之前一直模糊不清,网上也搜不到现成的答案。经过多方资料搜集整理。写出此文供大家一起参阅。由于涉及众多非常底层的知识,我假设读者已经对操作系统和磁盘存取有一定的基础知识。文中如有疏漏,还请大佬指正。   为了探究这个问题,我们要先来回顾一下我之前的一篇文章《文件随机或顺序读写原理深入浅出》讲的文件存储的底层原理知识。如下图所示。一个文件的数据是以块为单位存储到物理磁盘的随机位置,这是由操作系统负责管理的,用户程序无权决定。所以在文件视图层面我们连续存储的数据,映射到物理磁盘层面就是随机位置了。图中是假设磁盘块大小为32KB,则文件对应的数据偏移地址存储到对应的物理块中示意图。

 

图2         图3                                                                             MySQL就是通过这种技巧,实现了修改数据文件时,不必像传统修改文件那样付出昂贵代价。这种方式虽然解决了修改文件时避免大规模移动数据的弊端,但是读取这些数据时,却无法像传统存取方式那样,直接从文件偏移地址0开始顺序读取。而是要根据页的链表结构顺序读取。需要不断的计算和移动文件偏移量指针,好在这个过程不会花费多少代价。但是会带来另外一个比较严重的问题就是页空洞,也称为碎片。上面行11有部分字段数据已经转移到了页⑥中,显然页⑥是没有存满的。行12是存在页④中的,这样就产生了碎片问题,浪费了文件的一些地址空间,这些空洞存的都是特殊占位符,也要占据真实的物理磁盘空间。随着更新删除操作越来越多,碎片也会越来越多,所以有必要定期进行表的碎片整理,这样可以收缩表文件占据的磁盘空间。也可以降低页链表的长度,从而节省一些寻址操作代价。   如果可变长字段值由大变小,则原来的字段值地址空间足够了,也就不需要新加页了,只需要重新整理排列一下当前更新的行数据即可。使得变成字段的值占用实际空间即可。至于留下的页碎片问题,MySQL也有相应的机制做合并优化操作。我这里不做深究。