【PGCCC】Postgresql Varlena 结构

news2025/1/23 4:45:07

前言

postgresql 会有一些变长的数据类型,存储都是采用 varlena 格式的(除了 cstring 类型),通过语句 SELECT typname FROM pg_type WHERE typlen = -1就可以看到所有采用 varlena 格式的数据类型,比如常见的 text ,json 类型。

varlena 结构

varlena结构有一个通用的定义格式,如下所示

struct varlena
{
	char		vl_len_[4];		/* Do not touch this field directly! */
	char		vl_dat[FLEXIBLE_ARRAY_MEMBER];	/* Data content is here */
};

注意这是通用格式,varlena还分为很多种格式,每种格式的定义都不相同。我们在使用之前,需要根据它的第一个字节,转换为它对应格式:

  1. 第一个字节等于1000 0000, 那么就是varattrib_1b_e,用来存储 external 数据(在 toast 会有讲解到)

  2. 第一个字节的最高位等于1,然后字节不等于1000 0000,那么就是varattrib_1b,用来存储小数据

  3. 第一个字节的最高位等于0,那么就是varattrib_4b,可以存储不超过1GB的数据

varattrib_1b 类型

varattrib_1b类型的格式如下:

typedef struct
{
	uint8		va_header;
	char		va_data[FLEXIBLE_ARRAY_MEMBER]; /* Data begins here */
} varattrib_1b;

va_header 只有 8 位,最高位是标记位,值为 1。剩余的 7 位表示数据长度,所以varattrib_1b类型只是用于存储长度不超过127 byte 的小数据。

-----------------------------------------
   tag   |         length               |   
-----------------------------------------
  1 bit  |        7 bit                 |
-----------------------------------------

varattrib_4b类型

varattrib_4b格式会根据存储的数据是否被压缩过分为两种。最高第二位为1,则表示存储的数据是未压缩的。为0,则表示存储的数据是压缩过的。varattrib_4b的定义如下,使用union来表示这两种情况。对于未压缩的数据,使用va_4byte结构体存储。对于压缩的数据,使用va_compressed结构体存储。

typedef union
{
    /* va_data存储的数据没有被压缩 */
	struct						
	{
		uint32		va_header;
		char		va_data[FLEXIBLE_ARRAY_MEMBER];
	}			va_4byte;
    
    /* va_data存储的数据被压缩过了 */
	struct						
	{
		uint32		va_header;
		uint32		va_rawsize; /* 原始数据的大小 */
		char		va_data[FLEXIBLE_ARRAY_MEMBER]; 
	}			va_compressed;
    
} varattrib_4b;

这两个结构体的第一个成员va_header都是 uint32 类型,两者的格式是一样的。它最高位是标记位,值为 0。第二位表示是否没被压缩。剩下的 30 位表示数据的长度,所以只能支持不超过 1GB (2^30 - 1 bytes) 的数据。

--------------------------------------------------
    tag    |    compress    |      length        |
--------------------------------------------------
   1 bit   |    1 bit       |      30 bit        |
-------------------------------------------------

varattrib_1b_e 类型

它并不存储数据,只是指向了外部数据的地址。根据外部数据的存储位置,可以分为几种格式。首先看看它的定义:

typedef struct
{
	uint8		va_header;		
	uint8		va_tag;			/* 类型 */
	char		va_data[FLEXIBLE_ARRAY_MEMBER];
} varattrib_1b_e;

第二个字节va_tag表示类型,有下面四种。每种类型下,它的 va_data存储的格式都不是一样的。

typedef enum vartag_external
{
	VARTAG_INDIRECT = 1,
	VARTAG_EXPANDED_RO = 2,
	VARTAG_EXPANDED_RW = 3,
	VARTAG_ONDISK = 18
} vartag_external;

外部数据存储在磁盘

如果是 VARTAG_ONDISK类型,它表示外部数据存储在磁盘中。 va_data存储的格式定义如下

typedef struct varatt_external
{
	int32		va_rawsize;		/* Original data size (includes header) */
	int32		va_extsize;		/* External saved size (doesn't) */
	Oid			va_valueid;		/* Unique ID of value within TOAST table */
	Oid			va_toastrelid;	/* RelID of TOAST table containing it */
}			varatt_external;

外部数据存储在内存

如果外部数据是存储在内存中,则对应VARTAG_EXPANDED_RO和VARTAG_EXPANDED_RW类型。两者唯一的区别是前者只读,后者可以读写。

typedef struct varatt_expanded
{
	ExpandedObjectHeader *eohptr;  // 指针
} varatt_expanded;

指针类型

还剩下一种特殊格式 VARTAG_INDIRECT,它只是一个varlena指针,可以指向varatt_external,varatt_expanded,或者是varattrib_1b,varattrib_4b 类型的原始数据。

typedef struct varatt_indirect
{
	struct varlena *pointer;	/* Pointer to in-memory varlena */
}			varatt_indirect;

使用

postgresql 提供了很多宏(在src/include/postgres.h文件),方便我们操作 varlena数据。下面以varattrib_4b类型为例
在这里插入图片描述
下面展示一个创建 varlena数据的例子

result = (struct varlena *) palloc(length + VARHDRSZ); // 分配堆内存
SET_VARSIZE(result, length + VARHDRSZ);   // 设置头部
memcpy(VARDATA(result), mydata, length); // 写入数据

设计思想

postgresql 设计了 varlena结构,主要是为了解决cstring的问题。我们知道 cstring在获取长度时,只能从头扫描到结尾,才能知道,这种效率是非常低的。varlena为了支持不同大小的数据,还要避免空间的浪费,所以对于小型数据,将长度的信息和标记位都融合在了一个字节里。因为外部数据格式只是存储了一个指针,并且数据长度都可以确定了,所以头个字节不需要存储长度信息,使用1000 0000仅仅作为标记。其余的格式就都归纳给varattrib_1b类型了,并且数据长度肯定是大于 0 的,所以不会有冲突。

对于大型的数据,长度信息就需要占用比较多的位来表示,所以 postgresql 采用了四个字节来存储。为了避免浪费,它将头两个位作为标记位使用了。可以看到 postgresql 对于数据格式的设计是非常精妙的,我们可以多多学习。

作者:zhmin
链接:https://zhmin.github.io/posts/postgresql-varlena/
#PG证书#PG考试#PostgreSQL培训#PostgreSQL考试#PostgreSQL认证

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2263508.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu搭建ES8集群+加密通讯+https访问

目录 写在前面 一、前期准备 1. 创建用户和用户组 2. 修改limits.conf文件 3. 关闭操作系统swap功能 4. 调整mmap上限 二、安装ES 1.下载ES 2.配置集群间安全访问证书密钥 3.配置elasticsearch.yml 4.修改jvm.options 5.启动ES服务 6.修改密码 7.启用外部ht…

LeetCode:144.前序遍历

跟着carl学算法,本系列博客仅做个人记录,建议大家都去看carl本人的博客,写的真的很好的! 代码随想录 LeetCode:144. 二叉树的前序遍历 给你二叉树的根节点 root ,返回它节点值的 前序 遍历。 示例 1&#x…

git remote -v(--verbose)显示你的 Git 仓库配置的远程仓库的详细信息

git remote -v 是一个 Git 命令,用于显示你的 Git 仓库配置的远程仓库的详细信息。 当你执行 git remote -v 命令时,你会看到类似以下的输出: origin https://github.com/your-username/your-repo.git (fetch) origin https://github.com…

Gin-vue-admin(4):项目创建前端一级页面和二级页面

目录 创建一级页面创建二级页面 创建一级页面 view目录下新建一个my&#xff0c;Index.vue <template></template><script> export default {name:My, } </script><script setup> import {ref} from vue const myNameref("name") &…

数据结构漫游记:初识vector

​ 嘿&#xff0c;各位技术潮人&#xff01;好久不见甚是想念。生活就像一场奇妙冒险&#xff0c;而编程就是那把超酷的万能钥匙。此刻&#xff0c;阳光洒在键盘上&#xff0c;灵感在指尖跳跃&#xff0c;让我们抛开一切束缚&#xff0c;给平淡日子加点料&#xff0c;注入满满的…

R语言混合模型回归GBTM群组轨迹模型绘图可视化研究

全文链接&#xff1a;https://tecdat.cn/?p38581 在回归分析的广袤领域中&#xff0c;面对具有多条未知函数线的复杂数据时&#xff0c;传统方法常常捉襟见肘。混合模型作为一种强有力的分析手段应运而生&#xff0c;其在处理此类复杂情境时展现出独特的优势与潜力&#xff08…

uniapp自定义树型结构数据弹窗,给默认选中的节点,禁用所有子节点

兼容H5、安卓App、微信小程序 实现逻辑&#xff1a;给默认选中节点的所有子节点添加一个disabled属性&#xff0c;以此禁用子节点。 /components/sonTreeNode/sonTreeNode.vue 封装成组件 <template><view><view :class"[item,item.is_level1?pL1:item…

水仙花数(流程图,NS流程图)

题目&#xff1a;打印出所有的100-999之间的"水仙花数"&#xff0c;并画出流程图和NS流程图。所谓"水仙花数"是指一个三位数&#xff0c;其各位数字立方和等于该数本身。例如&#xff1a;153是一个"水仙花数"&#xff0c;因为1531的三次方&#…

【C++读写.xlsx文件】OpenXLSX开源库在 Ubuntu 18.04 的编译、交叉编译与使用教程

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a; 2024-12-17 …

Kioptix Level 2靶场练习保姆级---春不晚

1.将靶机导入至vm中 首先将靶机的网络设置为nat模式&#xff0c;然后在kali中使用arp-scan命令查找靶机ip 靶机ip为&#xff1a;61.139.2.130 arp-scan -l 2.使用nmap扫描目标ip的端口 nmap -p- 61.139.2.130 3.对存在端口进行服务版本和、系统版本、默认脚本检测 nmap -p…

电子元器件与电路之-MOS管的介绍和作用

一、基本概念 MOS 管&#xff0c;或MOSFET&#xff0c;全称是Metal-Oxide-Semiconductor Field-Effect Transistor&#xff08;金属 - 氧化物 - 半导体场效应晶体管&#xff09;。和三极管利用电流控制电流不同&#xff0c;它是一种利用电场效应来控制电流的半导体器件。和三级…

异地组网最简单的方法

01、使用硬件路由器的VPN功能 这是一种相对简单且常用的异地组网方法。你需要有支持VPN功能的路由器&#xff0c;如华硕、中兴等品牌。在主站点的路由器上配置VPN服务器&#xff0c;并在异地设备上通过操作系统自带的VPN连接功能添加一个VPN连接&#xff0c;输入主站点路由器的…

【GO环境安装】mac系统+GoLand使用

文章目录 下载安装包环境配置GoLandGo Modules 下载安装包 地址&#xff1a;GO下载地址 下载好后直接进行安装&#xff1a; 进入terminal&#xff0c;查看是否安装成功&#xff1a; 环境配置 在文稿下面创建工作目录&#xff1a; 在文稿下新建Go_Works文件夹&#xff0c;在…

点击数字层级从 admin.vue 跳转到 inviter-list.vue 组件

文章目录 1、admin.vue2、inviter-list.vue 1、admin.vue 好的&#xff0c;我们来分析一下代码中“层级”这一列的逻辑&#xff0c;并探讨它与后端的关联。 “层级” 列的逻辑 在您的代码中&#xff0c;“层级”列的渲染逻辑如下&#xff1a; <el-table-columnalign&quo…

LabVIEW实时信号采集与频谱分析

系统通过LabVIEW与PXIe硬件结合&#xff0c;实现高精度模拟信号的实时采集、频谱分析与可视化显示。核心功能包括采样率配置、快速傅里叶变换&#xff08;FFT&#xff09;、功率谱图生成及动态缩放调整&#xff0c;同时支持信号平均与噪声抑制。系统设计灵活&#xff0c;适用于…

【ComfyUI + 铅笔素描画风】艺术家DaTou发布了的彩色铅笔素描风格生成(真实感超强)

发布时间&#xff1a;2024年12月09日 项目主页&#xff1a;https://hf-mirror.com/Datou1111/shou_xin 基础模型&#xff1a;flux.1-dev comfyui工作流下载&#xff1a;https://pan.baidu.com/s/1FrLQ4o8ldckKwhIrN1Pv7g?pwd1220 自己测试 官方效果 生成猫猫 shou_xin, a m…

洛谷 B3644 【模板】拓扑排序 / 家谱树 C语言

题目&#xff1a; https://www.luogu.com.cn/problem/B3644 题目描述 有个人的家族很大&#xff0c;辈分关系很混乱&#xff0c;请你帮整理一下这种关系。给出每个人的后代的信息。输出一个序列&#xff0c;使得每个人的后辈都比那个人后列出。 输入格式 第 1 行一个整数 …

unity接入coze智能体

官网链接 coze智能体创建、设置 点击创建–选着智能体&#xff0c;随便起一个名字&#xff0c;就可以了 添加令牌 把随便起一个名字&#xff0c;设置时间&#xff0c;把所有选项都勾选上&#xff0c;一定要勾选所有团队空间&#xff0c;否则无法点击确定。 点击确定后&a…

EE308FZ_Sixth Assignment_Beta Sprint_Sprint Essay 3

Assignment 6Beta SprintCourseEE308FZ[A] — Software EngineeringClass Link2401_MU_SE_FZURequirementsTeamwork—Beta SprintTeam NameFZUGOObjectiveSprint Essay 3_Day5-Day6 (12.15-12.16)Other Reference1. WeChat Mini Program Design Guide 2. Javascript Style Guid…

国内主流的工程项目管理软件有哪些?

随着科技的发展&#xff0c;工程管理软件已经成为了工程管理的重要工具。在国内&#xff0c;有许多优秀的工程管理软件&#xff0c;它们可以帮助我们更好地管理工程项目。那么&#xff0c;你知道有哪些工程管理软件吗&#xff1f;下面就让我们一起来盘点一下。 1、广联达 广联…