千家信息网

怎么从零学习PostgreSQL Page结构

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章主要为大家展示了"怎么从零学习PostgreSQL Page结构",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"怎么从零学习PostgreSQL P
千家信息网最后更新 2026年11月03日怎么从零学习PostgreSQL Page结构

这篇文章主要为大家展示了"怎么从零学习PostgreSQL Page结构",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"怎么从零学习PostgreSQL Page结构"这篇文章吧。

一、Page

pg中的page和Oracle中的数据块一样,指的是数据库的块,操作系统块的整数倍个,默认是8K也就是两个操作系统块(4k的文件系统块)。这个大小在pg编译安装configure的时候通过--with-blocksize参数指定,单位是Kb。

二、Page的内部结构

2.1 page结构

2.2 PageHeaderData数据结构 (页头)

可以看到一个Page有 Pager header(页头),后面是linp(行指针),pd_lower和pd_upper分别是空闲空间的开始位置和结束位置;后面就是行数据(pg里面的行就是tuple)和special空间。整个page的结构比Oracle的数据块结构简单多了。

typedef struct PageHeaderData

{

/* XXX LSN is member of *any* block, not only page-organized ones */

PageXLogRecPtr pd_lsn; /* LSN: next byte after last byte of xlog

* record for last change to this page */

uint16 pd_checksum; /* checksum */

uint16 pd_flags; /* flag bits, see below */

LocationIndex pd_lower; /* offset to start of free space */

LocationIndex pd_upper; /* offset to end of free space */

LocationIndex pd_special; /* offset to start of special space */

uint16 pd_pagesize_version;

TransactionId pd_prune_xid; /* oldest prunable XID, or zero if none */

ItemIdData pd_linp[FLEXIBLE_ARRAY_MEMBER]; /* line pointer array */

} PageHeaderData;

具体的长度和描述也都有详细说明:

Field

Type

Length

Description

pd_lsn

PageXLogRecPtr

8 bytes

LSN: next byte after last byte of WAL record for last change to this page

pd_checksum

uint16

2 bytes

Page checksum

pd_flags

uint16

2 bytes

Flag bits

pd_lower

LocationIndex

2 bytes

Offset to start of free space

pd_upper

LocationIndex

2 bytes

Offset to end of free space

pd_special

LocationIndex

2 bytes

Offset to start of special space

pd_pagesize_version

uint16

2 bytes

Page size and layout version number information

pd_prune_xid

TransactionId

4 bytes

Oldest unpruned XMAX on page, or zero if none

简单来说,pd_lsn是指最后修改过这个page的lsn(log sequence number),这个和wal(write ahead log,同oracle redo)中记录的lsn一致。数据落盘时redo必须先刷到wal,这个pd_lsn就记录了最后data落盘时的相关redo的lsn。

pd_checksum是校验和,在initdb初始化实例的时候通过-k参数指定开启,默认是关闭的,initdb之后不能修改,它基于FNV-1a hash算法,做了相应的更改。这个校验和与Oracle的checksum一样用于数据块在读入和写出内存时的校验。比如我们在内存中修改了一个数据块,写入到磁盘的时候,在内存里面先计算好checksum,数据块写完后再计算一遍cheksum是否和之前在内存中的一致,确保整个写出过程没有出错,保护数据结构不被破坏。

pd_flags有以下的值:

/*

* pd_flags contains the following flag bits. Undefined bits are initialized

* to zero and may be used in the future.

*

* PD_HAS_FREE_LINES is set if there are any LP_UNUSED line pointers before

* pd_lower. This should be considered a hint rather than the truth, since

* changes to it are not WAL-logged.

*

* PD_PAGE_FULL is set if an UPDATE doesn't find enough free space in the

* page for its new tuple version; this suggests that a prune is needed.

* Again, this is just a hint.

*/

#define PD_HAS_FREE_LINES 0x0001 /* are there any unused line pointers? */

#define PD_PAGE_FULL 0x0002 /* not enough free space for new tuple? */

#define PD_ALL_VISIBLE 0x0004 /* all tuples on page are visible to

* everyone */

#define PD_VALID_FLAG_BITS 0x0007 /* OR of all valid pd_flags bits */

pd_lower和pd_upper分别表示空闲空间起始位置和结束位置;pd_special在索引page才有效;pd_pagesize_version是page大小和page version的存储位,在不同数据库版本中,page version不一样:

数据库版本

pd_pagesize_version



<7.3

0



7.3 & 7.4

1



8.0

2



8.1

3



>8.3

4



prune_xid表示这个page上最早删除或者修改tuple的事务id,在vacuum操作的时候会用到。(pg没有undo,旧的数据也在page中,用vacuum来清理)

2.3 linp结构(行指针)

lp_off是tuple的开始的偏移量;lp_flags是标志位;lp_len记录了tuple的长度。

Field

Length

Description

lp_off

15 bits

offset to tuple

lp_flags

2 bits

State of iteam pointer

lp_len

15 bits

Byte length of tuple

2.4 tuple header结构(行头)

typedef struct HeapTupleFields

{

TransactionId t_xmin; /* inserting xact ID */

TransactionId t_xmax; /* deleting or locking xact ID */

union

{

CommandId t_cid; /* inserting or deleting command ID, or both */

TransactionId t_xvac; /* old-style VACUUM FULL xact ID */

} t_field3;

} HeapTupleFields;

typedef struct DatumTupleFields

{

int32 datum_len_; /* varlena header (do not touch directly!) */

int32 datum_typmod; /* -1, or identifier of a record type */

Oid datum_typeid; /* composite type OID, or RECORDOID */

/*

* Note: field ordering is chosen with thought that Oid might someday

* widen to 64 bits.

*/

} DatumTupleFields;

struct HeapTupleHeaderData

{

union

{

HeapTupleFields t_heap;

DatumTupleFields t_datum;

} t_choice;

ItemPointerData t_ctid; /* current TID of this or newer tuple (or a

* speculative insertion token) */

/* Fields below here must match MinimalTupleData! */

uint16 t_infomask2; /* number of attributes + various flags */

uint16 t_infomask; /* various flag bits, see below */

uint8 t_hoff; /* sizeof header incl. bitmap, padding */

/* ^ - 23 bytes - ^ */

bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]; /* bitmap of NULLs */

/* MORE DATA FOLLOWS AT END OF STRUCT */

};

(*这部分代码在src/include/access/htup_details.h)

也有对应的长度和描述的相详细说明:

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_xvac

TransactionId

4 bytes

XID for VACUUM operation moving a row version

t_ctid

ItemPointerData

6 bytes

current TID of this or newer row version

t_infomask2

uint16

2 bytes

number of attributes, plus various flag bits

t_infomask

uint16

2 bytes

various flag bits

t_hoff

uint8

1 byte

offset to user data

union是共享结构体,起作用的变量是最后一次赋值的成员。来看看tuple header的结构。

在HeapTupleFields中,t_xmin是插入这行tuple的事务id;t_xmax是删除或者锁住tuple的事务id;union结构中的t_cid是删除或者插入这个tuple的命令id,也就是命令序号;t_xvac是以前格式的vacuum full用到的事务id。

在DatumTupleFields中,datum_len_ 指tuple的长度;datum_typmod是记录的type;datum_typeid是记录的id。

页头HeapTupleHeaderData包含了union结构体中的两个变量HeapTupleFields和DatumTupleFields。t_ctid是tuple id,类似oracle的rowid,形式为(块号,行号)。

t_infomask2 表示属性和标志位

t_infomask 是flag标志位,具体值如下:

/*

* information stored in t_infomask:

*/

#define HEAP_HASNULL 0x0001 /* has null attribute(s) */

#define HEAP_HASVARWIDTH 0x0002 /* has variable-width attribute(s) */

#define HEAP_HASEXTERNAL 0x0004 /* has external stored attribute(s) */

#define HEAP_HASOID 0x0008 /* has an object-id field */

#define HEAP_XMAX_KEYSHR_LOCK 0x0010 /* xmax is a key-shared locker */

#define HEAP_COMBOCID 0x0020 /* t_cid is a combo cid */

#define HEAP_XMAX_EXCL_LOCK 0x0040 /* xmax is exclusive locker */

#define HEAP_XMAX_LOCK_ONLY 0x0080 /* xmax, if valid, is only a locker */

/* xmax is a shared locker */

#define HEAP_XMAX_SHR_LOCK (HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)

#define HEAP_LOCK_MASK (HEAP_XMAX_SHR_LOCK | HEAP_XMAX_EXCL_LOCK | \

HEAP_XMAX_KEYSHR_LOCK)

#define HEAP_XMIN_COMMITTED 0x0100 /* t_xmin committed */

#define HEAP_XMIN_INVALID 0x0200 /* t_xmin invalid/aborted */

#define HEAP_XMIN_FROZEN (HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID)

#define HEAP_XMAX_COMMITTED 0x0400 /* t_xmax committed */

#define HEAP_XMAX_INVALID 0x0800 /* t_xmax invalid/aborted */

#define HEAP_XMAX_IS_MULTI 0x1000 /* t_xmax is a MultiXactId */

#define HEAP_UPDATED 0x2000 /* this is UPDATEd version of row */

#define HEAP_MOVED_OFF 0x4000 /* moved to another place by pre-9.0

* VACUUM FULL; kept for binary

* upgrade support */

#define HEAP_MOVED_IN 0x8000 /* moved from another place by pre-9.0

* VACUUM FULL; kept for binary

* upgrade support */

#define HEAP_MOVED (HEAP_MOVED_OFF | HEAP_MOVED_IN)

#define HEAP_XACT_MASK 0xFFF0 /* visibility-related bits */

t_hoff表示tuple header的长度

t_bits记录了tuple中null值的列

三、实验

3.1 安装pageinspect

它在源码的crontrib目录下面

postgres@cs-> cd postgresql-10.4/contrib/pageinspect

make && make install

postgres@cs-> make

postgres@cs-> make install

create extension就好了

postgres@cs-> psql

psql (10.4)

Type "help" for help.

postgres=# CREATE EXTENSION pageinspect;

CREATE EXTENSION

postgres=# \x

Expanded display is on.

postgres=# \dx

List of installed extensions

-[ RECORD 1 ]------------------------------------------------------

Name | pageinspect

Version | 1.6

Schema | public

Description | inspect the contents of database pages at a low level

-[ RECORD 2 ]------------------------------------------------------

Name | plpgsql

Version | 1.0

Schema | pg_catalog

Description | PL/pgSQL procedural language

3.2 创建建测试表t1,插入数据

这里可以看到1000行数据用了6个数据块来存储(这里数据块从0开始),第6个数据块包含了73条记录(tuple)

3.3 Pageinspect查看page

这里我们通过两个函数来查看

page_header 可以看到页头的数据

heap_pageitems 可以看到具体tuple的数据

3.3.1 page_header

postgres=# \xExpanded display is on.postgres=# select * from page_header(get_raw_page('t1',0));-[ RECORD 1 ]--------lsn | 0/1671188checksum | 0flags | 0lower | 772upper | 784special | 8192pagesize | 8192version | 4prune_xid | 0postgres=#

可以看到第0个page的pd_lsn为0/1671188,checksum和flags都是0,这里没有开启checksum;tuple开始偏移是772(pd_lower),结束偏移是784(pd_upper),这个page是个表,所以它没有special,我们看到的sepcial就是8192了;pagesize是8192就是8K,version是4,没有需要清理的tuple,所以存储需要清理的tuple的最早事务的id就是0(prune_xid)。

3.3.2 heap_page_items

我们来看一行记录,可以看到它是第1行记录(lp=1),tuple的开始偏移量8160(lp_off),tuple的长度是32 bytes(lp_len为32,这个tuple是第一个插入的tuple,所以lp_off+lp_len=8160+32=8192),这行记录的插入事务id是557(t_min),和tuple的删除事务id是0(tmax),这里数据没有被删除,所以都是0。我们还可以看到t_ctid是(0,1),这里表示这个tuple是这个page中第一个块的第一条tuple;tinfomask2是2,t_infomask为2306,十六进制就是 0x0902 ,这个我们可以根据上面提到的值去看看具体的含义,0x0902 = 0x0100 + 0x0800 +0x0002;tuple头部结构(行头)的长度是24(t_hoff),t_data就是16进制存储的真正的数据了。

3.4 删除一行数据观察prune_xid

我们删除一行tuple可以看到prune_xid有了值,为559,这个559就是删除这个tuple的事务id(当前最早的删除或更改了tuple的事务id)

同样,我们可以看到lp为1的这个tuple的t_xmax为559,这里就是删除这行tuple的事务id。

PostgreSQL Page的物理结构相比Oracle的数据块来说简单很多了,源代码开放也便于学习和研究,pg是个很好很强大的数据库,值得好好学习。

以上是"怎么从零学习PostgreSQL Page结构"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

数据 结构 事务 就是 学习 长度 位置 内存 数据库 时候 偏移 存储 一行 两个 内容 标志 空间 篇文章 系统 一致 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 广州淘业互联网络科技 互联网科技活动banner 互联网科技保险 互联网科技有限公司经营范围 互联网科技小贷 华中科技大学互联网 亿人帮互联网科技 互联网科技汛 剑昆互联网络科技有限公司临桂 成都铂石互联网科技做什么的 厦门比较好的科技互联网公司 互联网公司科技股 重庆互联网医院沙龙医盟信息科技 青海科技产业互联网发展 中国科技创新与世界互联网大会 西安小鹰速贷互联网科技有限公司 工业互联网展湾科技股份有限公司 半导体行业属于互联网高科技类吗 互联网时代高科技布局 互联网科技和医药行业 咖啡网 厦门中拓互联网络科技有限公司 互联网 科技创业 友谊互联网络科技 狮子座互联网科技培训 互联网科技咨询 北京华百购互联网科技有限公司 以后互联网后是啥科技 成都铂石互联网科技做什么的 深圳市罗太互联网科技有限公司
0