likes
comments
collection
share

Postgresql 页结构解析

作者站长头像
站长
· 阅读数 15

Postgresql 页结构

一般来说,数据表数据物理存储在非易失性存储设备上面,PG也不例外。如下图所示,数据表中的数据存储在N个数据文件中,每个数据文件有N个Page(大小默认为8K,可在编译安装时指定)组成。Page为PG的最小存取单元。

Postgresql 页结构解析

数据页(Page)

数据页Page由页头、数据指针数组(ItemIdData)、可使用的空闲空间(Free Space)、实际数据(Items)和特殊空间(Special Space)组成。

  • 页头存储LSN号、校验位等元数据信息,占用24Bytes。
  • 数据指针数组存储指向实际数据的指针,数组中的元素ItemId可理解为相应数据行在Page中的实际开始偏移,数据行指针ItemID由三部分组成,前15位为Page内偏移,中间2位为标志,后面15位为长度。
  • 空闲空间为未使用可分配的空间,ItemID从空闲空间的头部开始分配,Item(数据行)从空闲空间的尾部开始。 - 实际数据为数据的行数据(每种数据类型的存储格式后续再解析)。
  • 特殊空间用于存储索引访问使用的数据,不同的访问方法数据不同。

Postgresql 页结构解析

pageinspect

pageinspect 是pg提供的一个插件,可以将页面的结构信息进行查看和分析。

CREATE EXTENSION pageinspect;

在使用之前要先安装该插件: Postgresql 页结构解析

查看page header信息

Postgresql 页结构解析 通过上图中的lower信息可以推算出该page中现有多少tuple(并不是查询表显示的数量,可能远大于它们的数量,因为数据的更新和删除的tuple不会立刻的清除,还可能被新插入的数据再次复用),page的每页有24bytes的页头西信息,每个item的指针是4bytes,那么(lower - 24)/4 就是tuple的数量;可以简单的验证下: (60 - 24)/4 = 9; 如下图所示: Postgresql 页结构解析

向表中插入一条新的数据:INSERT INTO t1 VALUES(2,2); insert前: Postgresql 页结构解析 insert后: Postgresql 页结构解析 通过上图可以看出数据新插入的数据的item新分配的,并且每行数据之间的便宜量是32bytes 「16096 - 16064」

查看page item信息

Postgresql 页结构解析

SELECT * FROM heap_page_items(get_raw_page('t1',0)); (t1是表名,0是页面号)

Postgresql 页结构解析 通过上图可知数据的顺序插入和lp_off之间的关系,并且可以看出数据存储是从页尾开始的

Postgresql 页结构解析 item从前往后写,tuple从后往前写,lower和upper相遇,那这个页就写完了。 item描述tuple的位置和长度.每次插入新item ,最多是从lower下一个字节开始,或者使用已有空闲的item.

vaccum 数据表

Postgresql 页结构解析

Postgresql 页结构解析 通过vaccum前后的结果可以可看出,在清理之后数据的指针没有回收,但页头重新做了标记,如下图:

Postgresql 页结构解析

查看page中的数据

SELECT get_raw_page::text FROM get_raw_page('t1', 0);

Postgresql 页结构解析 Postgresql 页结构解析

通过上面的两个图更清晰的展示出page存储的方式了,前面的是item指针,指向数据在page中的位置,后面存储的是实际的数据,中间的0表示空闲的空间。