今天在处理个磁盘告警时,对一些膨胀率较高的表进行了vacuum full操作,但是经过漫长的等待之后发现竟然没有回收多少空间,一查死元组竟然没啥变化,坑爹啊!
至于原因是啥,我们先来简单了解下vacuum full的过程。
我们都知道vacuum full本质上是创建了一张新的表,会创建该表的一个新拷贝,并且在操作完成之前都不会释放旧的拷贝。因此在进行vacuum full操作的时候是会加上一个ACCESS EXCLUSIVE级别的锁,所以一般只有当我们需要从表中回收大量磁盘空间的,即膨胀率很高的表才会去做vacuum full的操作。
正因为vacuum full会进行数据的重组,保留页面最小大小,释放磁盘空间。所以我们在源码中也可以发现vacuum full不是和普通的vacuum放在一起,而是和cluster放在一块,即在src/backend/commands/cluster.c中。
下面我来看看一张普通的表进行vacuum full的大致过程:
cluster_rel(){ rebuild_relation(){ make_new_heap() copy_table_data() finish_heap_swap(){ swap_relation_files() reindex_relation() performDeletion() RelationMapRemoveMapping() } } }
首先主函数是cluster_rel,cluster_rel调用rebuild_relation,正因为如此,所以vacuum full其实是表重建的一个过程,而rebuild_relation函数会调用三个大的步骤,make_new_heap->copy_table_data->finish_heap_swap。先创建新的临时表,然后拷贝数据,最后调用finish_heap_swap函数完成切换,finish_heap_swap又分为交换数据文件、重建索引、清理临时表、清除映射关系几个步骤。
从源码中看make_new_heap会调用heap_create_with_catalog()函数进行新的临时表创建,表名为pg_temp_%u。
copy_table_data函数的过程