postgresql page页结构

2023-05-16

前言
postgresql 保存数据的基本单位是 page,一个 page 里包含多条数据。postgresql 同磁盘的读写单位也是 page,一个 page 对应于磁盘的一个 block。block 的格式和 page 是相同的,本篇文章详细得介绍了 page 的数据存储格式和相关的增删改查操作。

内存结构
page 可以简单划分为四块区域:

page 头部区域,描述整个 page 的情况,比如空闲空间,校检值等
数据指针区域,数据指针用来描述实际数据的存储信息
数据区域,用来存储实际数据
特殊区域,用来存储一些特殊数据
在这里插入图片描述

其中数据指针区域和数据区域是空间共享的,数据指针区域的区间是从上面开始的,向下扩展。而数据区域的空间方向是相反的,从下面开始的,向上扩展。

每条数据存储在 page 里,都对应一个数据指针和一个数据,数据指针记录了实际存储数据的位置。这种共享机制能够充分的利用空间,无论每条数据的是否过大或过小,都能几乎填满整个 page。

Page 头部
page 头部由结构体PageHeaderData来表示,

typedef struct PageHeaderData
{
	PageXLogRecPtr pd_lsn;	// 该数据页最后一次被修改对应的wal日志的位置
	uint16		pd_checksum;	// 校检值
	uint16		pd_flags;	// 标记位
	LocationIndex pd_lower;	// 空闲空间的起始偏移量
	LocationIndex pd_upper;	// 空闲空间的结束偏移量
	LocationIndex pd_special;	// 特殊空间的结束偏移量
	uint16		pd_pagesize_version;	// page 格式版本号
	TransactionId pd_prune_xid; /* oldest prunable XID, or zero if none */
	ItemIdData	pd_linp[FLEXIBLE_ARRAY_MEMBER]; // 数据指针数组
} PageHeaderData;

当新添加一条数据到 page 里,需要快速判断是否有空闲空间。page 的 pd_flags 记录了 page 是否有空闲空间,它的标记位如下:

#define PD_HAS_FREE_LINES 0x0001 // 是否有空闲的数据指针
#define PD_PAGE_FULL 0x0002 // 是否有空闲空间支持添加一条数据
#define PD_ALL_VISIBLE 0x0004 /* all tuples on page are visible to everyone */
注意到 pd_linp 成员,它是一个 ItemIdData 数组,这里需要把它看成一个指针。它并不属于头部,从计算头部的长度就可以看出

#define SizeOfPageHeaderData (offsetof(PageHeaderData, pd_linp))
整个结构如下图所示:
在这里插入图片描述

数据指针
ItemData 结构表示数据的指针,它描述了数据的位置和状态

typedef struct ItemIdData
{
	unsigned	lp_off:15,		// 数据在page的偏移量
				lp_flags:2,		// 状态值,有unused,normal,redirect,dead
				lp_len:15;		// 数据长度
} ItemIdData;

lp_flags 只有2位,它有四种状态值:

#define LP_UNUSED 0 // 表示此指针是空闲
#define LP_NORMAL 1 // 表示此指针正在被使用,且对应的数据已经存储
#define LP_REDIRECT 2 // HOT redirect (should have lp_len=0) */
#define LP_DEAD 3 // dead, may or may not have storage */
插入数据
PageAddItemExtended函数负责插入数据,定义如下

/*

  • 参数item是要写入的数据,参数size是数据的长度
  • 参数offsetNumber指定数据指针的位置,如果对于位置没有要求,值为InvalidOffsetNumber
  • 参数flags是标记位,可以指明数据类型是否是tuple类型,还可以指定是否覆盖已有数据
    */
    OffsetNumber PageAddItemExtended(Page page, Item item, Size size, OffsetNumber offsetNumber, int flags);
    如下图所示,原来的 page 有三条数据 data0、data2、data3,而 data 1 数据已经被删除,所以数据指针 ItemIdData 1 的位置是空闲的,现在要插入 data4 数据。

中间的图片展示了两种插入情况,没有指定数据指针的位置,和指定了数据指针位置为第2个(也就是原有的 ItemData 1 空闲位置)并且指定了覆盖选项。

后面的图片展示了指定数据指针的位置第三个(也就是为原有 ItemData2 的位置)。

在这里插入图片描述

插入数据的原理总结如下:

如果没有指定数据指针的位置,那么会尽量使用空闲位置的,通过检查 PD_HAS_FREE_LINES 标记位,就可以判断page 是否有空闲数据指针。如果有空闲位置,那么就从头开始遍历,直到找到一个空闲位置。如果没有前面空闲位置,只能使用 pd_lower 指向的位置。
如果指定了数据指针位置,并且设置了覆盖选项,那么首先会去检查该位置的指针是否已经被使用,如果没有被使用则直接修改指针属性和插入数据,否则就会报错。
如果指定了数据指针位置,但没有指定覆盖,那么不管此位置是否空闲,都需要将后面的指针后移一位。
删除数据
PageIndexTupleDelete负责删除指定位置的数据,删除数据后,会将需要将空闲的数据指针和数据进行压缩合并。

void PageIndexTupleDelete(Page page, OffsetNumber offnum);
下图展示了数据删除的过程,这里需要删除数据 data 2:

在这里插入图片描述

首先将数据指针删除,然后将后面的数据向上移动,填满空缺位。

然后将实际的存储数据删除,将后面的数据向下移动,填补空缺位。

最后还需要更新数据指针的 offset 属性,因为其对应的数据存储位置已经发生了改变。

修改数据
bool PageIndexTupleOverwrite(Page page, OffsetNumber offnum, Item newtup, Size newsize);
如果原有数据的大小和新数据相同,那么直接修改对应的数据指针和实际的数据。

如果不一致,需要先将数据进行删除,然后将删除的空间进行压缩合并,并且更新所有数据指针的 offset 属性。最后才完成添加数据。

作者:zhmin
链接:https://zhmin.github.io/posts/postgresql-buffer-page/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

postgresql page页结构 的相关文章

  • 在 Linux 中,Distinct SQL 无法与 UNNEST 一起使用

    当我在窗口系统中运行此查询时 行为正确 UNNEST 但是当我运行这个查询时 Linux 的行为不同 unnest 重复记录列表在不同的行上 SELECT DISTINCT billing billmanagement creation d
  • 让 django 不插入某些字段

    我有一个针对 postgresql 数据库表的 Django 模型 我希望 Django 在对象创建期间不要插入 field 3 作为 DB 应该填写的时间戳字段 class AbcModel model id models AutoFie
  • 如何在 JSON Postgres 数据类型列中搜索特定字符串?

    我有一个名为params在名为的表中reports其中包含 JSON 我需要找到 JSON 数组中任何位置包含文本 authVar 的行 我不知道文本可能出现的路径或级别 我只想使用标准的 like 运算符搜索 JSON 就像是 SELEC
  • 如何使用diesel-rs选择色谱柱的子集?

    我现在花了几个小时的时间来查询表的可用列的子集以及在其中包含计算 我知道这不是在选择查询中执行计算的最佳方式 但现在 我只是在开发一个原型 它应该是可行的 我在用diesel rs作为后端实现中所有数据库操作的 ORM 数据将存储在 Pos
  • Postgres 服务器性能在达到一定数量的记录后急剧下降

    我正在使用游标从大型 postgres 表中检索记录 4亿条记录 使用子表对数据进行分区 我的游标定义为 select from parent table order by indexed column 同时使用 JDBC 和 psql 前
  • 将 PostgreSQL 扩展安装到所有模式

    我在 PostgresQL 9 1 1 上尝试扩展unaccent http www postgresql org docs 9 1 static unaccent html适用于所有模式 所以我运行了命令CREATE EXTENSION
  • 如何更改 PostgreSQL 表中列的数据类型?

    在 PostgreSQL 交互式终端中输入以下命令会导致错误 ALTER TABLE tbl name ALTER COLUMN col name varchar 11 更改列的数据类型的正确命令是什么 请参阅此处的文档 http www
  • PostGIS Homebrew 安装引用旧路径?

    我在 OS X Mountain Lion 上升级并随后安装了 PostGIS 和 PostgreSQL 当尝试使用 PostGIS 扩展时 我收到以下错误 ERROR could not open extension control fi
  • 如何在 PostgreSql 的预订表中找到第一个空闲时间

    预订表包含预订开始日期 开始时间和持续时间 工作日的开始时间为工作时间 8 00 18 00 以半小时为增量 持续时间也以每天半小时为增量 CREATE TABLE reservation startdate date not null s
  • 执行 INSERT into 数据库后如何获取插入行的 id?

    我正在使用 c 11 和 pqxx 访问 postgresql 数据库 我需要插入行的 id 和标志 如果成功与否 执行 INSERT into 数据库后如何获取插入行的 id 我试图在网上找到例子但没有成功 work txn conn t
  • Postgres 简单的“数据透视表”

    如果我有一个这样的数据表 name type count test blue 6 test2 red 3 test red 4 我怎样才能查询它以获得一个表 name num red num blue test 4 6 test2 3 0
  • PostgreSQL C 函数建议

    有人可以给我一个关于自定义函数的初步尝试的提示吗 我需要用 2 个参数构造查询 一个 varchar 和一个 unix 时间戳 一个整数 我花了 3 个小时才得到下面的几行结果 查询测试可以是 select from pdc posot c
  • PostgreSQL 中字符串列类型的索引数组

    是否可以在类型为的列上创建索引文本数组 尝试使用GIN索引 但查询似乎没有使用这些索引 Example CREATE TABLE users name VARCHAR 100 groups TEXT Query SELECT name FR
  • 无法安装 psycopg2 (pip install psycopg2)

    我使用的是 MAC 和 python 版本 2 7 14 Collecting psycopg2 Could not fetch URL https pypi python org simple psycopg2 There was a p
  • PostgreSQL 性能 - SELECT 与存储函数

    我正在尝试在 PostgreSQL 上创建一个存储函数来提高性能并存储大查询 并且只需在我的代码中调用该函数即可 例如 如果我有一个函数 CREATE OR REPLACE FUNCTION test max integer RETURNS
  • 插入多行并返回主键时 Sqlalchemy 的奇怪行为

    插入多行并返回主键时 我注意到一些奇怪的事情 如果我在 isert 查询中添加使用参数值 我会得到预期的行为 但是当将值传递给游标时 不会返回任何内容 这可能是一个错误还是我误解了什么 我的sqlachemy版本是0 9 4 下面如何重现错
  • 如何在 pgAdmin III 中为多个表生成 CREATE 脚本?

    在 pgAdmin III 中您可以 右键单击表格 scripts 创建脚本 从 SQL 编辑器保存脚本 如果必须对多个表执行此操作 是否有一种方法可以将脚本合并到一个文件中 除了手动复制粘贴它们之外 如果这可以通过 psql 提示符或 p
  • 使用两个日期之间的随机日期时间更新每一行

    我有一个专栏叫date created我希望每一行保存一个随机日期 日期距当前时间为 2 天 我正在运行以下查询 但它会更新具有相同随机日期的所有行 我希望每一行都是随机的并且不相同 update table set date create
  • 查找 PostgreSQL 中所有范围集合的所有交集

    我正在寻找一种有效的方法来查找时间戳范围集之间的所有交集 它需要与 PostgreSQL 9 2 配合使用 假设这些范围代表一个人可以见面的时间 每个人都可以有一个或多个空闲时间范围 我想找到all可以召开会议的时间段 即所有人都有空的时间
  • 用户登录时的 Postgresql 触发器

    我正在尝试找出一种方法来了解用户何时登录 Postgres 数据库 有没有办法定义用户登录数据库时触发的触发器 或者是否有一个表或系统视图在任何人登录数据库时都会更新 登录钩子 https github com splendiddata l

随机推荐

  • 傻妞恢复包带短信登录(迟来的恢复包)

    傻妞恢复包 magisk模块就不启动青龙 xff0c 添加下容器就可以 目录全部在 data data com termux files home local share tmoe linux containers proot ubuntu
  • A1153

    题意 xff1a 输入准考证号 xff0c 考试分数 然后输入查询命令 xff0c 对每个命令按照要求模拟输出 思路分析 xff1a 命令为1 xff1a 表示查询考 级的所有记录 xff0c 按照成绩从大到小排名 xff0c 成绩相同则按
  • 电脑显示WiFi已连接,但无法访问internet怎么解决?

    我在玩游戏的时候电脑突然卡崩了 xff0c 我无奈的重启了一下 xff0c 结果电脑重启后连不上网了 xff0c 我开始以为还在重新连接 xff0c 在等待 xff0c 过了好久才发现其实早就连上wifi了 xff0c 但显示无法连接int
  • Python-Django-模型

    一 ORM 模型介绍 1 ORM 模型 对象关系映射 xff08 英语 xff1a Object Relational Mapping xff0c 简称ORM xff0c 或ORM xff0c 或OR mapping xff09 xff0c
  • LeetCodeWeeklyContest-159

    最近看了篇文章 xff0c 文章里说 希望你身边能有个比你聪明五倍 xff0c 但却比你还努力十倍的人 倍数虽然有些夸张 xff0c 但是这个思想还是能get到的 5230 缀点成线 在一个 XY 坐标系中有一些点 xff0c 我们用数组
  • 获取安卓设备唯一标识方法总结

    安卓设备的唯一标识的方法并不唯一 xff0c 也没有哪种方法能够适用于所有的Android设备 xff0c 下面列出几种常见的方式 xff0c 可以根据需要选择 1 IMEI 码 IMEI xff08 国际移动设备识别码 xff09 唯一编
  • Anaconda安装及环境变量配置(Ubuntu)

    安装Anaconda 下载软件 Anaconda下载地址打开终端 xff0c 进入到安装包的存放路径输入命令 xff1a span class token function bash span namexxxxx span class to
  • 快速幂——原理及实现

    这篇文章讲一下快速幂的问题 xff1b 首先问一个简单的问题 xff1a 23是几 xff1f 很简单啊 xff0c 是不是 xff1f 答案是8 xff1b 那么是怎么得来的呢 xff1f 222 61 8 xff1b 连续乘了3次2 x
  • 适合小白的几个入门级Python ocr识别库

    1 pytesseract 2 PaddleOCR 3 easyocr 4 muggle ocr 5 dddd ocr 6 其他 工作生活中经常会遇到需要提取图片中文字信息的情况 xff0c 以前都是手动自己把图片里的字敲出来 xff0c
  • WSL使用中遇到坑

    1 开机启动配置项 在WSL中配置的一些服务如nginx xff0c mysql xff0c ssh等 xff0c 每次开机都会需要手动开启 xff0c 参考网上的开机服务配置都是通过往 etc rc local里面添加启动脚本 xff0c
  • 云服务器Ubuntu(无桌面)安装远程桌面

    如果主机上安装的ubuntu是桌面版 xff0c 打开桌面共享即可使用Windows的远程桌面进行链接 详细参考ubuntu20 10中设置桌面共享的三种方式 任选其一 的第一部分 本文主要说明如何在Ubuntu云服务器上安装远程桌面 一
  • win10解决photoshop打不开问题

    win10 的权限跟win7有些地方不一样 xff0c 对于一直使用win7的人可能很不习惯 xff0c 我在win10上面用photoshop的时候 xff0c 出现打不开photoshop的时候 xff0c 如果你也有类似的情况 xff
  • iOS UIAlertController控件

    UIAlertController取代UIAlertView和UIActionSheet xff0c 用于界面弹出一个警告视图 初始化方法 xff0c UIAlertControllerStyle分为UIAlertControllerSty
  • 用递归和非递归实现斐波那契数列(C语言)

    斐波那契数列 xff08 Fibonacci sequence xff09 xff0c 又称黄金分割数列 因数学家列昂纳多 斐波那契 xff08 Leonardoda Fibonacci xff09 以兔子繁殖为例子而引入 xff0c 故又
  • cmd设置全局环境变量和用户环境变量

    register env bat 64 echo off echo add sg generator evn 输出空行echo set generator home 61 cd echo SG GENERATOR HOME generato
  • 如何下载4399游戏到本地并修改数值

    一直很纠结mac不能玩什么游戏 xff0c 只能通过4399来解乏了 8过4399的页面过于臃肿 xff0c 无法安心玩游戏 xff0c 于是有了这个想法 至于修改数值嘛 xff0c 嘿嘿 测试环境 xff1a mac air m1 43
  • g++版本控制,apt安装g++11

    安装g 43 43 11 span class token function sudo span add apt repository y ppa ubuntu toolchain r test span class token funct
  • git设置代理

    设置全局代理 http span class token function git span config global https proxy http 127 0 0 1 1080 https span class token func
  • Collecting package metadata (current_repodata.json)解决方法

    先运行命令conda clean i看看是否有效 删除 condarc文件 使用 conda config set show channel urls true 重新生成
  • postgresql page页结构

    前言 postgresql 保存数据的基本单位是 page xff0c 一个 page 里包含多条数据 postgresql 同磁盘的读写单位也是 page xff0c 一个 page 对应于磁盘的一个 block block 的格式和 p