# 70.6. Database Page Layout

70.6.1. Table Row Layout

This section provides an overview of the page format used withinPostgreSQL tables and indexes.[17]Sequences and TOAST tables are formatted just like a regular table.

In the following explanation, abyteis assumed to contain 8 bits. In addition, the termitemrefers to an individual data value that is stored on a page. In a table, an item is a row; in an index, an item is an index entry.

Every table and index is stored as an array ofpagesof a fixed size (usually 8 kB, although a different page size can be selected when compiling the server). In a table, all the pages are logically equivalent, so a particular item (row) can be stored in any page. In indexes, the first page is generally reserved as ametapageholding control information, and there can be different types of pages within the index, depending on the index access method.

Table 70.2shows the overall layout of a page. There are five parts to each page.

Table 70.2. Overall Page Layout

Item Description
PageHeaderData 24 bytes long. Contains general information about the page, including
free space pointers.
ItemIdData Array of item identifiers pointing to the actual items. Each
entry is an (offset,length) pair. 4 bytes per item.
Free space The unallocated space. New item identifiers are allocated from
the start of this area, new items from the end.
Items 实际物品本身。
特殊空间 索引访问方法特定的数据。不同的方法存储不同的
数据。在普通表中为空。

每页的前 24 个字节由页头(页头数据)。它的格式在表 70.3.第一个字段跟踪与此页面相关的最新 WAL 条目。第二个字段包含页面校验和,如果数据校验和已启用。接下来是一个包含标志位的 2 字节字段。接下来是三个 2 字节整数字段 (pd_lower,pd_upper, 和pd_special)。这些包含从页面开始到未分配空间开始、到未分配空间结束和特殊空间开始的字节偏移量。页头的下 2 个字节,pd_pagesize_version,存储页面大小和版本指示符。从 PostgreSQL 8.3 开始,版本号为 4;PostgreSQL 8.1 和 8.2 使用版本号 3;PostgreSQL 8.0 使用版本号 2;PostgreSQL 7.3 和 7.4 使用版本号 1;以前的版本使用版本号 0.(这些版本中基本的页面布局和标题格式没有改变,但堆行标题的布局有。)页面大小基本上只是作为交叉检查出现;不支持在安装中使用多个页面大小。最后一个字段是一个提示,显示修剪页面是否可能有利可图:它跟踪页面上最旧的未修剪 XMAX。表 70.3.

PageHeaderData 布局

场地 类型 长度 描述
pd_lsn PageXLogRecPtr 8 个字节 LSN:WAL 记录最后一个字节之后的下一个字节,用于最后一次更改此页面
pd_校验和 uint16 2 个字节 页校验和
pd_旗帜 uint16 2 个字节 标志位
pd_降低 位置索引 2 个字节 到可用空间开始的偏移量
pd_上 位置索引 2 个字节 到可用空间末端的偏移量
pd_特别的 位置索引 2 个字节 特殊空间起点的偏移量
pd_页面大小_版本 uint16 2 个字节 页面大小和布局版本号信息
pd_修剪_xid 交易 ID 4字节 页面上最旧的未修剪 XMAX,如果没有则为零

所有细节都可以在src/include/storage/bufpage.h.

页眉之后是项目标识符(ItemIdData),每个需要四个字节。项目标识符包含项目开头的字节偏移量、其长度(以字节为单位)和一些影响其解释的属性位。根据需要从未分配空间的开头分配新的项目标识符。存在的项目标识符的数量可以通过查看来确定pd_lower,增加它以分配一个新的标识符。因为项目标识符在被释放之前永远不会移动,因此它的索引可以长期用于引用项目,即使项目本身在页面上移动以压缩可用空间也是如此。实际上,每个指向项目的指针 (项目指针,也称为CTID) 由 PostgreSQL 创建的,由页码和项目标识符的索引组成。

项目本身存储在未分配空间末尾向后分配的空间中。确切的结构因表要包含的内容而异。表和序列都使用名为HeapTupleHeaderData, described below.

The final section is the “special section” which can contain anything the access method wishes to store. For example, b-tree indexes store links to the page's left and right siblings, as well as some other data relevant to the index structure. Ordinary tables do not use a special section at all (indicated by settingpd_specialto equal the page size).

Figure 70.1illustrates how these parts are laid out in a page.

Figure 70.1. Page Layout

# 70.6.1. Table Row Layout

All table rows are structured in the same way. There is a fixed-size header (occupying 23 bytes on most machines), followed by an optional null bitmap, an optional object ID field, and the user data. The header is detailed inTable 70.4. The actual user data (columns of the row) begins at the offset indicated byt_hoff, which must always be a multiple of the MAXALIGN distance for the platform. The null bitmap is only present if theHEAP_HASNULLbit is set int_infomask. If it is present it begins just after the fixed header and occupies enough bytes to have one bit per data column (that is, the number of bits that equals the attribute count int_infomask2). In this list of bits, a 1 bit indicates not-null, a 0 bit is a null. When the bitmap is not present, all columns are assumed not-null. The object ID is only present if theHEAP_HASOID_OLDbit is set int_infomask. If present, it appears just before thet_hoffboundary. Any padding needed to maket_hoffa MAXALIGN multiple will appear between the null bitmap and the object ID. (This in turn ensures that the object ID is suitably aligned.)

Table 70.4. HeapTupleHeaderData Layout

Field Type Length Description
t_xmin TransactionId 4 bytes insert XID stamp
t_xmax TransactionId 4 bytes delete XID stamp
t_cid CommandId 4 bytes insert and/or delete CID stamp (overlays with t_xvac)
t_真空吸尘器 交易 ID 4字节 用于 VACUUM 操作移动行版本的 XID
吨_ctid 项目指针数据 6字节 此行或更新行版本的当前 TID
吨_信息掩码2 uint16 2 个字节 属性数量,以及各种标志位
吨_信息掩码 uint16 2 个字节 各种标志位
吨_霍夫 uint8 1 个字节 对用户数据的偏移

所有细节都可以在src/include/access/htup_details.h.

只能使用从其他表中获得的信息来解释实际数据,主要是pg_attribute.识别字段位置所需的关键值是阿特伦对齐.没有办法直接获取特定属性,除非只有固定宽度的字段且没有空值。所有这些诡计都包含在函数中堆_获取属性,快速获取属性堆_获取系统属性.

要读取数据,您需要依次检查每个属性。首先根据空位图检查该字段是否为NULL。如果是,请转到下一个。然后确保你有正确的对齐方式。如果该字段是一个固定宽度的字段,那么所有的字节都被简单地放置。如果它是一个可变长度字段(attlen = -1),那么它会更复杂一些。所有可变长度数据类型共享公共头结构结构 varlena,其中包括存储值的总长度和一些标志位。根据标志,数据可以是内联的,也可以在 TOAST 表中;它也可能被压缩(参见第 70.2 节)。