在PostgreSQL中释放项目标识符之后,如何重用空间?

问题描述

最近,我开始对Postgresql的可用空间管理和碎片整理进行一些研究。我知道堆上的每个页面都包含一个页面标题页面标识符,可用空间和项目。当插入一个新的元组时,一个新的项目标识符将被插入到可用空间的开头,而新的项目数据将被插入到可用空间的结尾。

使用Vacuum后,死元组的项目标识符和项目数据将被删除。如果删除的项目标识符在其他标识符中间,则标识符之间将存在间隙。由于通常新标识符将在空闲空间的开头添加,因此之间的空闲空间是否会再次重用?如果是这样,我们如何找到这个空间?

以下是这种情况的直观示例:

page after Vacuum

删除一些元组后,(0,3)和(0,5)之间有未使用的空间。如何再次使用此空间? 谢谢!

解决方法

假定该表包含2页。我们看一下第一页(第0页),假设插入了一些数据,并且该页有3个元组(行)。现在,如果说我们删除元组2,则PG删除2号元组,并对其余元组重新排序以进行碎片整理,然后更新此页面的FSM和VM。 PostgreSQL继续执行此过程,直到最后一页(真空)。

当您清理真空时,不会删除不必要的行指针,以后将重新使用它们。

因为,如果删除了行指针,则必须更新关联索引的所有索引元组。

,

PostgreSQL的术语“项目标识符”是“行指针”。 “项目指针”或“元组标识符”是页码和行指针(图像中的(0,5))的组合。

乍看之下,这种间接操作很尴尬,但是优点是可以在不更改元组地址的情况下,随时重新整理实际的元组数据以对可用空间进行碎片整理。

行指针在页面标题之后形成一个数组。当应将新的元组添加到缓冲区时,可以使用任何自由行指针。如果没有空闲的行指针,则在数组末尾添加新的行指针。作为参考,请参阅PageAddItemExtended中的src/backend/storage/page/bufpage.c

,

除非将页面截断并随后重新添加,否则不会压缩行指针数组。添加新的元组时,未使用的阵列插槽将被重用。如果该页面曾经充满大量小元组,然后删除并重新填充了少量大元组,那么将有多余的未使用lp占用少量空间,这些空间将永远不会被重用。

您可以将pageinspect中的heap_page_items与where lp_off=0一起使用。