postgresql修炼之道_PostgreSQL的TOAST技术

547a85cb-f023-eb11-8da9-e4434bdf6706.png

本文参考:

  • PostgreSQL TOAST 技术理解
  • 《PostgreSQL修炼之道》

一、TOAST是什么?

TOAST是“The Oversized-Attribute Storage Technique”(超尺寸属性存储技术)的缩写,主要用于存储一个大字段的值。

要理解TOAST,我们要先理解页(BLOCK)的概念。在PG中,页是数据在文件存储中的基本单位,其大小是固定的且只能在编译期指定,之后无法修改,默认的大小为8KB。同时,PG不允许一行数据跨页存储。那么对于超长的行数据,PG就会启动TOAST,将大的字段压缩或切片成多个物理行存到另一张系统表中(TOAST表),这种存储方式叫行外存储

二、使用TOAST

只有特定的数据类型支持TOAST,因为那些整数、浮点数等不太长的数据类型是没有必要使用TOAST的。

另外,支持TOAST的数据类型必须是变长的。在变长类型中:

  • 前4字节(32bit)称为长度字,长度字后面存储具体的内容或一个指针。
  • 长度字的高2bit位是标志位,后面的30bit是长度值(表示值的总长度,包括长度字本身,以字节计)。
  • 由长度值可知TOAST数据类型的逻辑长度最多是30bit,即1GB(2^30-1字节)之内。
  • 前2bit的标志位,一个表示压缩标志位,一个表示是否行外存储,如果两个都是零,那么表示既未压缩也未行外存储。
  • 如果设置了压缩标志标志位,表示该数值被压缩过(使用的是非常简单且快速的LZ压缩方法),使用前必须先解压缩。
  • 如果设置了行外存储标志位,则表示该数值是在行外存储的。此时,长度字后面的部分只是一个指针,指向存储实际数据的TOAST表中的位置。如果两个标志位都设置了,那么这个行外数据也会被压缩。不管是哪种情况,长度字里剩下的30bit的长度值都表示数据的实际尺寸,而不是压缩后的长度。

557a85cb-f023-eb11-8da9-e4434bdf6706.png

在 PG 中每个表字段有四种 TOAST 的策略:

  • PLAIN —— 避免压缩和行外存储。只有那些不需要 TOAST 策略就能存放的数据类型允许选择(例如 int 类型),而对于 text 这类要求存储长度超过页大小的类型,是不允许采用此策略的。
  • EXTENDED —— 允许压缩和行外存储。一般会先压缩,如果还是太大,就会行外存储。这是大多数可以TOAST的数据类型的默认策略。
  • EXTERNAL —— 允许行外存储,但不许压缩。这让在text类型和bytea类型字段上的子串操作更快。类似字符串这种会对数据的一部分进行操作的字段,采用此策略可能获得更高的性能,因为不需要读取出整行数据再解压。
  • MAIN —— 允许压缩,但不许行外存储。不过实际上,为了保证过大数据的存储,行外存储在其它方式(例如压缩)都无法满足需求的情况下,作为最后手段还是会被启动。因此理解为:尽量不使用行外存储更贴切。

首先创建一张 blog 表,查看它的各字段的TOAST策略:

postgres=# create table blog(id int, title text, content text);
CREATE TABLE
postgres=# d+ blog;Table "public.blog"Column  |  Type   | Modifiers | Storage  | Stats target | Description 
---------+---------+-----------+----------+--------------+-------------id      | integer |           | plain    |              | title   | text    |           | extended |              | content | text    |           | extended |              |

可以看到,interger 默认 TOAST 策略为 PLAIN ,而 text 为 EXTENDED

另外可以修改某个字段系统默认分配的TOAST策略,假如要将上面blog表中的content字段的TOAST策略改成EXTERNAL,就可以这样:

ALTER TABLE blog ALTER content SET STORAGE EXTERNAL; 

三、TOAST表的结构

如果一个表中有任何一个字段是可以TOAST的,那么PostgreSQL会自动为该表建一个相关联的TOAST表,其OID存储在pg_class系统表的reltoastrelid记录里,行外的内容保存在TOAST表里。

查看blog表对应的TOAST表的OID:

postgres=# select relname,relfilenode,reltoastrelid from pg_class where relname='blog';relname | relfilenode | reltoastrelid 
---------+-------------+---------------blog    |       16441 |         16444
(1 row)

通过上述语句,我们查到 blog 表的 oid 为16441,其对应 TOAST 表的 oid 为16444(关于 oid 和 pg_class 的概念,请参考PG官方文档),那么其对应 TOAST 表名则为: pg_toast.pg_toast_16441(注意这里是 blog 表的 oid )。

行外存储被切成了多个Chunk块,每个Chunk块大约是一个BLOCK的四分之一大小,如果块大小为8KB(默认就是8KB),则Chunk大约为2KB(比2KB略小一点),每个Chunk都作为独立的行存储在TOAST表中。

TOAST表有三个字段:

  • chunk_id —— 用来表示特定 TOAST 值的 OID ,可以理解为具有同样 chunk_id 值的所有行组成原表(这里的 blog )的 TOAST 字段的一行数据。
  • chunk_seq —— 用来表示该行数据在整个数据中的位置。
  • chunk_data —— 该Chunk实际的数据。

我们看下上面的TOAST表pg_toast.pg_toast_16441的定义:

postgres=# d+ pg_toast.pg_toast_16441;
TOAST table "pg_toast.pg_toast_16441"Column   |  Type   | Storage 
------------+---------+---------chunk_id   | oid     | plainchunk_seq  | integer | plainchunk_data | bytea   | plain

在chunk_id和chunk_seq上有一个唯一的索引,提供对数值的快速检索。

因此,一个表示行外存储的指针数据中包括了要查询的TOAST表的OID和特定数值的chunk_id(也是一个OID类型)。为了方便,指针数据还存储了逻辑数据的尺寸(原始的未压缩的数据长度)及实际存储的尺寸(如果使用了压缩,则两者不同)。加上头部的长度字,一个TOAST指针数据的总尺寸是20字节。

四、TOAST技术实践

现在我们来实际验证下TOAST:

postgres=# insert into blog values(1, 'title', '0123456789');
INSERT 0 1
postgres=# select * from blog;id | title |  content   
----+-------+------------1 | title | 0123456789
(1 row)postgres=# select * from pg_toast.pg_toast_16441;chunk_id | chunk_seq | chunk_data 
----------+-----------+------------
(0 rows)

可以看到因为 content 只有10个字符,所以没有压缩,也没有行外存储。然后我们使用如下 SQL 语句增加 content 的长度,每次增长1倍,同时观察 content 的长度,看看会发生什么情况?

postgres=# update blog set content=content||content where id=1;
UPDATE 1
postgres=# select id,title,length(content) from blog;id | title | length 
----+-------+--------1 | title |     20
(1 row)
postgres=# select * from pg_toast.pg_toast_16441;chunk_id | chunk_seq | chunk_data 
----------+-----------+------------
(0 rows)

反复执行如上过程,直到 pg_toast_16441 表中有数据:

postgres=# select id,title,length(content) from blog;id | title | length 
----+-------+--------1 | title | 327680
(1 row)postgres=# select chunk_id,chunk_seq,length(chunk_data) from pg_toast.pg_toast_16441;chunk_id | chunk_seq | length 
----------+-----------+--------16439 |         0 |   199616439 |         1 |   1773
(2 rows)

可以看到,直到 content 的长度为327680时(已远远超过页大小 8K),对应 TOAST 表中才有了2行 数据,且长度都是略小于2K,这是因为 extended 策略下,先启用了压缩,然后才使用行外存储。

下面我们将 content 的 TOAST 策略改为 EXTERNAL ,以禁止压缩。

postgres=# alter table blog alter content set storage external;
ALTER TABLE
postgres=# d+ blog;Table "public.blog"Column  |  Type   | Modifiers | Storage  | Stats target | Description 
---------+---------+-----------+----------+--------------+-------------id      | integer |           | plain    |              | title   | text    |           | extended |              | content | text    |           | external |              |

然后我们再插入一条数据:

postgres=# insert into blog values(2, 'title', '0123456789');
INSERT 0 1
postgres=# select id,title,length(content) from blog;id | title | length 
----+-------+--------1 | title | 3276802 | title |     10
(2 rows)

然后重复以上步骤,直到 pg_toast_16441 表中有数据:

postgres=# update blog set content=content||content where id=2;
UPDATE 1
postgres=# select id,title,length(content) from blog;id | title | length 
----+-------+--------2 | title | 3276801 | title | 327680
(2 rows)postgres=# select chunk_id,chunk_seq,length(chunk_data) from pg_toast.pg_toast_16441;chunk_id | chunk_seq | length 
----------+-----------+--------16447 |         0 |   199616447 |         1 |   177316448 |         0 |   199616448 |         1 |   199616448 |         2 |   1996....(省略)16448 |       164 |   1996
(167 rows)

因为不允许压缩,所以新的操作在TOAST表中生成了更多Chunk块行记录。通过以上操作得出以下结论:

  • 如果策略允许压缩,则TOAST优先选择压缩。
  • 不管是否压缩,一旦数据超过2KB左右,就会启用行外存储。
  • 修改TOAST策略,不会影响现有数据的存储方式。

五、TOAST技术总结

TOAST比那些更直接的方法(比如允许行值跨越多个页面)有更多优点。 假设查询通常是用相对比较短的键值进行匹配的,那么执行器的大多数工作都将使用主行项完成。TOAST过的属性的大值只是在把结果集发送给客户端的时候才被抽出来(如果它被选中)。 因此,主表要小得多,并且它的能放入到共享缓冲区中的行要比没有任何行外存储的方案更多。 排序集也缩小了,并且排序将更多地在内存里完成。一个小测试表明,一个典型的保存 HTML 页面以及它们的 URL 的表占用的存储(包括TOAST表在内)大约只有裸数据的一半,而主表只包含全部数据的 10%(URL和一些小的 HTML 页面)。与在一个非TOAST的对照表里面存储(把全部 HTML 页面裁剪成 7Kb 以匹配页面大小)同样的数据相比,运行时没有任何区别。

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

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

相关文章

3D器官和骨骼将使移植清单成为历史

来源:IEEE电气电子工程师学会对于患有慢性病或病情危重的患者,等待器官移植匹配的时间可能对生命生死攸关。根据美国卫生资源和服务管理局(Health Resources and Services Administration:https://www.organdonor.gov/statistics-…

11月25号站立会议

小组名称:飞天小女警 项目名称:礼物挑选小工具 小组成员:沈柏杉(组长)、程媛媛、杨钰宁、谭力铭 代码地址:HTTPS: https://git.coding.net/shenbaishan/GIFT.git SSH:gitgit.coding.net:shenbai…

鱼c论坛python课后作业_三日速成python?打工人,小心钱包,别当韭菜

随着人工智能的热度越来越高,许多非计算机专业的同学们也都纷纷投入到学习编程的道路上来。而Python,作为一种相对比较容易上手的语言,也越来越受欢迎。网络上各类网课层出不穷,各式广告令人眼花缭乱。某些课程甚至卖出“天价”&a…

Linux shell的输入输出

echo --echo命令可以显示文本行或变量,或者把字符串输入到文件 --echo [option] string-e 解析转义字符 例如:echo -e "nimenhao\nasfdsaf" 打印发生换行-n 回车不换行 详解:一般在命令行打印字符串,光标会…

区块链共识算法的发展现状与展望

来源:平行区块链摘 要 共识算法是区块链技术的核心要素, 也是近年来分布式系统研究的热点. 本文系统性地梳理和讨论了区块链发展过程中的 32 种重要共识算法, 介绍了传统分布式一致性算法以及分布式共识领域的里程碑式的重要研究和结论, 提出了区块链共识算法的一种…

iphone打字怎么换行_iPhone电池保养指南

虽然手机电池的使用寿命会随着用户的日常使用慢慢减少、但需要注意的是、一些不恰当的操作方法,会导致电池寿命快速下降。这时候会有人说,那我可以换电池呀虽然换电池之后,一开始确实还可以,但是随着不恰当的使用,又开…

vc2017 linux printf,C/C++中自定义信息输出——printf与宏的配合使用

在C/C中,提起“宏”多少有些皱眉,至少我在入门C时旁人好心提醒:尽可能地使用typedef与const常量定义来替代“宏”的使用:1. 类型宏定义#define HANLE void*//可以替换为:typedef void *HANLE;2. 常量定义#define MAX_L…

这是我看过,最好懂的神经网络

来源:图灵教育猜一猜,下图中是什么动物?图1 看图猜动物尽管图中的动物胖得出奇,你也应该能够猜到它是一只长颈鹿。人类的大脑拥有强大的辨识能力,它是一个由差不多 800 亿个神经元组成的复杂网络。即使某物并非我们熟知…

上位机软件用什么写的_python7天训练营 | 为什么大家都开始用python写论文了?...

谈及保研,“内卷”被大家吵得沸沸扬扬。但其实,不仅是夏令营申请竞争、推免资格评比等环节,就连最基本的论文,也开始卷了起来。就以大家最常写的实证类论文为例:前两年,很多社科和经管的学科,夏…

美国如何发展脑科技

来源:蓝海长青智库作者:王小理、韩雪、薛淮大脑是理解自然和人类本身的“终极疆域”,脑科技是科研领域“皇冠上的明珠”。相比欧洲“人类脑计划”的迟缓,美国“推进创新神经技术脑研究计划”(BRAIN)进展颇为…

关于mysql ERROR 1045 (28000)错误的解决办法

错误情景: 使用Navicat打开mysql的时候弹出错误框 错误代码: ERROR 1045 (28000): Access denied for user ODBClocalhost (using password: NO) ERROR 1045 (28000): Access denied for user ODBClocalhost (using password: YES) 解决步骤: 1.找到配置文件my.ini &#xff0…

欧洲将研究具备自学习能力的无人机“蜂群”

来源:空天防务观察2019年10月23日,美国《防务新闻》网站报道称:芬兰将发展人工智能列为其领导欧洲联盟理事会六个月任期的关键目标,并提出了“压制防空无人机蜂群”(SEAD Swarm)项目,以迷惑、瘫…

表格打印没有左边线_office办公软件Excel表格的打印技巧,建议收藏

很多新手使用办公软件过程中,对于Excel的打印出现了诸多问题,今天我们就一起来看看表格打印的几个技巧!打印预览时网格线怎么不见了?如何调整打印区域的页边距?如何设置单色打印?......这些打印时遇到的麻烦…

符号说明表怎么做_能看懂这些房屋施工图,说明你家装修没问题了

一、基本知识1、标高1.1绝对标高亦称绝对高程或海拔高度,我国把青岛附近黄海的平均海平面定为绝对标高的零点,全国各地的标高均以此为基准。1.2标高是把某地点对应的绝对标高定义为0.000,(如名辉12#楼27.5)也称相对标高。建筑中一般以一层室内地面对应的绝对标高为0…

【ARM-Linux开发】U-Boot启动过程--详细版的完全分析

------------------------------------------------------------------------------------------------------------------------------------------- 我们知道,bootloader是系统上电后最初加载运行的代码。它提供了处理器上电复位后最开始需要执行的初始化代码。 在…

一文看懂RISC-V:异构IoT时代全新架构

来源: 芯潮近两年来,在ARM和Intel主导的竞争格局中,新的开源指令集架构RISC-V在芯片江湖声名鹊起。我们将指令集分为三种:1、复杂指令集(CISC):x86;2、精简指令集(RISC&a…

谷粒商城三阶段课件_苏科版初中物理九年级上册二、变阻器公开课优质课课件教案视频...

课题: 14.2变阻器教学目标:1.知道滑动变阻器的构造及工作原理。2.能画出滑动变阻器的结构示意图和符号。3.会正确连接和使用滑动变阻器。4.了解生活中变阻器的一些应用。教学重点、难点:重点&a…

小牛地图矢量抓取工具_SEO优化网站sitemap需要注意哪些要点才能很好的被百度蜘蛛抓取...

SEO优化网站sitemap需要注意哪些要点才能很好的被百度蜘蛛抓取一、全部链接真实有效。地图的主要目的是方便搜索引擎蜘蛛抓取的,如果地图存在死链,会影响网站在搜索引擎中网站权重的,要仔细检查有无错误的链接地址,提交前通过站长…

【加州理工】什么是模仿学习(Imitation Learning(模仿学习), 这62页ppt带你了解进展...

来源:专知【导读】Imitation Learning(模仿学习)机器学习新的研究热点之一,因其能很好的解决强化学习中的多步决策(sequential decision)问题,近段时间得到了广泛关注。那么模仿学习近期的前沿进…

ios12完美深色模式插件_分屏插件更新支持 A12,一心二用真滴爽

在众多iOS越狱插件中,总有几款亘古不变的插件一直深受大家的喜爱,分屏类插件就是其中之一。之前少年也介绍过几款好用的分屏 App,但是因为自己手持“真香” XR 机,而之前介绍的插件也一直没有适配 A12 设备,所以一直没…