【PGCCC】Postgresql Toast 原理

前言

上篇博客讲述了 postgresql 如何存储变长数据,它的应用主要是在 toast 。Toast 在存储大型数据时,会将它存储在单独的表中(称为 toast 表)。因为 postgresql 的 tuple(行数据)是存在在 Page 中的,Page 的大小默认为 8KB。postgresql 不允许 tuple 跨页存储,所以当一行数据的某个列数据过大时,比如 text 类型的数据,超过了单页的大小,那么 postgresql 会将它压缩,切分,并且存储在另外的位置。这种技术就是称为 Toast。

Toast 表

如果我们创建了一张表,有了变长数据的列,那么就会有一个对应的 toast 表,专门存储过大的数据。下面展示了一个例子

test=# \d mytableTable "public.mytable"Column |  Type   | Collation | Nullable | Default 
--------+---------+-----------+----------+---------id     | integer |           | not null | name   | text    |           |          | 
Indexes:"mytable_pkey" PRIMARY KEY, btree (id)

可以看见 mytable 有个变长数据类型的列 name。然后我们来看看表对应的 oid。

test=# select oid from pg_class where relname = 'mytable';oid   
--------127295
(1 row)

可以看到 mytable 表的 oid 为 127295,那么可以推断出它的 toast 表名称为 pg_toast_127295,其对应的 oid 仍然可以通过上述语句查出来(在此省略了),或者

test=# select reltoastrelid from pg_class where relname = 'mytable';reltoastrelid 
---------------127298
(1 row)

我们继续来看看 pg_toast_127295 表有哪些列

test=# select attname, typname from pg_attribute inner join pg_type ON pg_type.oid = pg_attribute.atttypid where pg_attribute.attrelid = 127298;attname   | typname 
------------+---------chunk_data | byteachunk_seq  | int4chunk_id   | oidtableoid   | oidctid       | tidxmin       | xidxmax       | xidcmin       | cidcmax       | cid
(9 rows)

除去下面的通用属性,它只定义了三列
在这里插入图片描述

切分数据

在这里插入图片描述
假设现在向 mytable 表插入一条大型数据,长度为3MB,里面存储了一张图片,采用了base64格式。

INSERT INTO mytable (name) values ('j7161gnb1u23 ...... 972bh6==');

postgresql 在处理这条请求时,发现 name 是 text 类型,并且这次插入的数据过大。那么首先它会被压缩,假设被压缩成 1MB,压缩后仍然不满足大小,然后按照指定的大小(默认为 2048 byte)切分成 512 份。每一份切片对应 toast 表的一行数据,它们的 chunk_id 都是相同的,因为属于同一个数据,只是 chunk_seq 不同,对应着切片位置。chunk_data 列就是存储着切片的数据。

数据结构

下面的图展示了普通表的 heap 数据和 toast 表的数据联系。
在这里插入图片描述
toast 表的数据格式在上面已经讲解过了,这里详细介绍了普通表的数据格式,它存储了 toast 表的对应数据位置。首先它是 varattrib_1b_e 数据类型,

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

它的 va_tag 类型为 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;

src/backend/access/common/toast_internals.c文件中的toast_save_datum函数实现了如何将数据存储到 toast 表,下面的程序经过简化处理了。

/*rel: 普通表value: 该列数据oldexternal: 用于更新用的
*/
Datum toast_save_datum(Relation rel, Datum value, struct varlena *oldexternal, int options) {struct varatt_external toast_pointer;Datum		t_values[3];t_values[0] = ObjectIdGetDatum(toast_pointer.va_valueid);t_values[2] = PointerGetDatum(&chunk_data);int32		chunk_seq = 0;  // 切片索引// 开始切分数据,data_todo 是剩余数据的长度while (data_todo > 0){int			i;// 计算切片长度chunk_size = Min(TOAST_MAX_CHUNK_SIZE, data_todo);// 记录 chunk_seq 列值t_values[1] = Int32GetDatum(chunk_seq++);// 记录切片数据, data_p 记录了写入的数据位置SET_VARSIZE(&chunk_data, chunk_size + VARHDRSZ);memcpy(VARDATA(&chunk_data), data_p, chunk_size);// 插入 toast 表toasttup = heap_form_tuple(toasttupDesc, t_values, t_isnull);heap_insert(toastrel, toasttup, mycid, options, NULL);// toast 表设置了 chunk_id 和 chunk_seq 的符合唯一索引for (i = 0; i < num_indexes; i++){if (toastidxs[i]->rd_index->indisready)index_insert(toastidxs[i], t_values, t_isnull,&(toasttup->t_self),toastrel,toastidxs[i]->rd_index->indisunique ?UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,NULL);}data_todo -= chunk_size;data_p += chunk_size;}}

切片策略

上面展示了 postgresql 对变长数据的默认切片策略,其实它还提供了别的策略。总共支持四种,如下所示:

PLAIN,数据不能被压缩,也不能存储到 toast 表
EXTENDED,默认策略,可以被压缩,也可以存储到 toast 表
EXTERNAL,不能被压缩,但可以存储到 toast 表
MAIN,可以被压缩,也可以存储到 toast 表,只不过它的优先级比EXTENDED低

技术比较

postgresql 并没有使用跨页存储的方案,而是将大型数据单独放到其余地方存储。这样在条件过滤时,会比较好,因为它不需要读取这些大的数据,而且只有当该列被选中时,才会在返回数据时去读取。这种场景下,减少了磁盘 IO 的读取,提升了性能。

同样它也有对应的缺点,那就是写入大型的数据时,会比较慢。因为它需要切片,然后插入到 toast 表中,还要更新 toast 表的索引。如果采用跨页存储,那么还可以利用磁盘顺序写的高性能。在读取整行数据时候,还需要先去寻找 toast 表的索引,然后再去读取 toast 表的数据,相比较跨页存储,仍然无法使用磁盘顺序读的高性能。
作者:zhmin
链接:https://zhmin.github.io/posts/postgresql-toast/
#PG证书#PG考试#postgresql培训#postgresql考试#postgresql认证

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C指针创建三维数组

定义的时候变量的位置就是最后一个星号的位置 int*** matrix3d_int(int nz, int nrh, int nch) {int*** matrix (int***)malloc(nz * sizeof(int**));for (int z 0; z < nz; z) {matrix[z] (int**)malloc(nrh * sizeof(int*));for (int y 0; y < nrh; y) {matrix[z][…

window下安装rust 及 vscode配置

安装 安装mingw64 &#xff08;c语言环境 选择posix-ucrt&#xff09; ucrt:通用c运行时库配置mingw64/bin的路径到环境变量中在cmd窗口中输入命令 "gcc -v" 4. 下载Rust安装程序 安装 Rust - Rust 程序设计语言 5. 配置rustup和cargo目录 &#xff08;cargo是包管…

wordpress搭建主题可配置json

网站首页展示 在线访问链接 http://dahua.bloggo.chat/ 配置json文件 我使用的是argon主题&#xff0c;你需要先安装好主题&#xff0c;然后可以导入我的json文件一键配置。 需要json界面配置文件的&#xff0c;可以在评论区回复&#xff0c;看见评论我会私发给你。~

基于表格滚动截屏(表格全部展开,没有滚动条)

import html2canvasPro from html2canvas // 截图&#xff0c;平辅表格 async function resetAgSize() {const allColumns gridApi.value.getColumns()let totalColumnWidth 0let totalColumnHeight 0// 遍历每一个行节点gridApi.value.forEachNode((rowNode) > {totalCo…

运行springBlade项目历程

框架选择 官网地址&#xff1a;https://bladex.cn 使用手册&#xff1a;https://www.kancloud.cn/smallchill/blade 常见问题&#xff1a;https://sns.bladex.cn/article-14966.html 问答社区&#xff1a;https://sns.bladex.cn 环境配置 存在jdk8的情况下安装jdk17 jdk17gi…

文件上传漏洞--理论

什么是文件上传漏洞&#xff1f; Web应用允许用户上传文件&#xff0c;但是没有对上传的文件进行严格的过滤和检测&#xff0c;导致网站执行了文件中包含的恶意代码。 漏洞的基本利用方式是&#xff1a; 成功上传包含恶意代码的文件&#xff0c;并在服务端成功执行该文件。 …

物联网(RFID)全景:被装信息化监控应用与挑战

一、被装物联网信息化建设的动因 信息化改革在20世纪80年代中期启航&#xff0c;旨在提升被装保障的效率。随着时间的推移&#xff0c;硬件的广泛运用和软件的快速迭代&#xff0c;装备业务在规划、制造、分发以及战时支援等核心环节&#xff0c;已经与信息系统深度融合&#x…

解决C盘空间不足的三种方案

方案一&#xff1a;网上盛传的C盘磁盘碎片整理&#x1f9e9;&#xff08;原理&#xff1a;将分散的文件片段整理到相邻的磁盘区域&#xff0c;减少文件的碎片化程度&#xff09;(效果不明显) 方案二&#xff1a;把其他盘的空间给C盘 &#x1f4bd;&#xff08;效果显著&#xf…

[项目代码] YOLOv5 铁路工人安全帽安全背心识别 [目标检测]

YOLOv5是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为一个回归问题&#xff0c;能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法&#xff08;如Faster R-CNN&#xff09;&#xff0c;YOLOv5具有更高的…

有什么初学算法的书籍推荐?

对于初学算法的读者&#xff0c;以下是一些值得推荐的书籍&#xff1a; 1、算法超简单&#xff1a;趣味游戏带你轻松入门与实践 作者&#xff1a;童晶 著 推荐理由&#xff1a;本书把趣味游戏应用于算法教学&#xff0c;提升读者的学习兴趣&#xff0c;并通过可视化的图解和动…

卸载一直显示在运行的应用

GX_work2: 打开文件 CtrlA全选卸载&#xff0c;他会显示有正在运行的软件点击跳过 然后打开被跳过的文件&#xff0c;CtrlA全选卸载 可能还是会显示有正在运行的软件点击跳过 直到出现.exe应用&#xff0c;最后打开任务管理器搜索此.exe应用&#xff0c;关闭它 最后完全卸载…

问:MySQL主从同步的机制梳理?

MySQL主从复制是一种数据库复制技术&#xff0c;通过将一个MySQL数据库服务器&#xff08;主节点&#xff09;的数据复制到一个或多个其他MySQL数据库服务器&#xff08;从节点&#xff09;&#xff0c;实现数据的自动同步。这种技术不仅提高了数据的可用性&#xff0c;还能通过…

基于BILSTM及其他RNN序列模型的人名分类器

数据集Kaggle链接 NameNationalLanguage | Kaggle 数据集分布: 第一列为人名,第二列为国家标签 代码开源地址 Kaggle代码链接 https://www.kaggle.com/code/houjijin/name-nationality-classification Gitee码云链接 人名国籍分类 Name Nation classification: using BI…

期权懂|期权新手入门教学:期权合约有哪些要素?

期权小懂每日分享期权知识&#xff0c;帮助期权新手及时有效地掌握即市趋势与新资讯&#xff01; 期权新手入门教学&#xff1a;期权合约有哪些要素&#xff1f; 期权合约&#xff1a;是指约定买方有权在将来某一时间以特定价格买入或卖出约定标的物的标准化或非标准化合约。期…

Oracle OCP认证考试考点详解082系列16

题记&#xff1a; 本系列主要讲解Oracle OCP认证考试考点&#xff08;题目&#xff09;&#xff0c;适用于19C/21C,跟着学OCP考试必过。 76. 第76题&#xff1a; 题目 解析及答案&#xff1a; 以下哪三项活动会被记录在数据库的警报日志中&#xff1f; A. 块损坏错误 数据库…

【Linux篇】面试——用户和组、文件类型、权限、进程

目录 一、权限管理 1. 用户和组 &#xff08;1&#xff09;相关概念 &#xff08;2&#xff09;用户命令 ① useradd&#xff08;添加新的用户账号&#xff09; ② userdel&#xff08;删除帐号&#xff09; ③ usermod&#xff08;修改帐号&#xff09; ④ passwd&…

论文阅读《机器人状态估计中的李群》

目录 摘要1 介绍2 微李理论2.1 李群2.2 group actions2.3 正切空间和李代数 摘要 李群是一个古老的数学抽象对象&#xff0c;可以追溯到19世纪&#xff0c;当时数学家 Sophus Lie奠定了连续变换群理论的基础。多年后&#xff0c;它的影响已经蔓延到科学和技术的各个领域。在机…

智能零售柜商品识别

项目源码获取方式见文章末尾&#xff01; 600多个深度学习项目资料&#xff0c;快来加入社群一起学习吧。 《------往期经典推荐------》 项目名称 1.【基于CNN-RNN的影像报告生成】 2.【卫星图像道路检测DeepLabV3Plus模型】 3.【GAN模型实现二次元头像生成】 4.【CNN模型实现…

综合案例铁锅炖(CSS项目大杂烩)

小工具&#xff1a;snipaste 全世界最好用的截图工具来了 Snipaste是一个强大简单的截图工具&#xff0c;方便的点就在于可以把截图贴回屏幕上 常用快捷方式有这些&#xff1a; 1.F1截图&#xff0c;同时测量大小&#xff0c;设置箭头&#xff0c;文字书写 2.F3在桌面置顶显示…

稀疏视角CBCT重建的几何感知衰减学习|文献速递-基于深度学习的病灶分割与数据超分辨率

Title 题目 Geometry-Aware Attenuation Learning forSparse-View CBCT Reconstruction 稀疏视角CBCT重建的几何感知衰减学习 01 文献速递介绍 稀疏视角锥形束计算机断层扫描&#xff08;CBCT&#xff09;重建的几何感知学习方法 锥形束计算机断层扫描&#xff08;CBCT&a…