PostgreSQL数据库不允许元组(行,记录)跨越多个页面(page)存储,所以,它不能直接存储非常大的字段值。对于大字段值,它将被压缩且(或)分解为多个物理行,该技术称为“TOAST”。

toast技术特点

  1. toast是超长字段在PG的一个存储方式;
  2. 全称The overSized Attribute Stroage Technique(超尺寸字段存储技术);
  3. 它会将大字段值压缩或者分散为多个物理行来存储;
  4. 对于用户来说不用关注这一技术实现,完全是透明的;

toast的存储方式

  • pg的部分类型数据支持toast,因为有些字段类型是不会产生大字段数据(比如date,time,boolean);
  • 支持toast的数据类型应当是可变长度的(variable-length);
  • 表中任何一个字段有toast,这个表都会有一个相关联的toast表,oid被存储在pg_class.reltoastrelid里;
  • 超出的数值会被分割成chunks,并且最多toast_max_chunk_size个byte(缺省是2KB);
  • 当存储的长度超过toast_tuple_threshold(通常是2KB),就会触发toast存储;
  • toast将会压缩或者移动字段值直到超过部分比toast_tuple_targer值小(这个值通常也是2KB)

建表时自动创建toast表

dellstore2=# create table toast_1(id int);
CREATE TABLE dellstore2=# select oid,relname,reltoastrelid from pg_class where relname = 'toast_1';
oid | relname | reltoastrelid
-------+---------+---------------
16498 | toast_1 | 0
(1 row) dellstore2=# create table toast_2(id int,info text);--其中info字段是text类型,则会自动产生toast表来存储。
CREATE TABLE
dellstore2=# select oid,relname,reltoastrelid from pg_class where relname = 'toast_2';
oid | relname | reltoastrelid
-------+---------+---------------
16501 | toast_2 | 16504
(1 row) dellstore2=# select oid,relname from pg_class where oid = 16504;
oid | relname
-------+----------------
16504 | pg_toast_16501
(1 row)

更改表的存储方式为toast

语法:

ALTER TABLE [ TABLE ] ALTER [ COLUMN ] column_name SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN }

dellstore2=# create table toast_0(info text);
CREATE TABLE
dellstore2=# \d+ toast_0
Table "public.toast_0"
Column | Type | Modifiers | Storage | Stats target | Description
--------+------+-----------+----------+--------------+-------------
info | text | | extended | | dellstore2=# alter table toast_0 alter column info set storage main;
ALTER TABLE
dellstore2=# \d+ toast_0
Table "public.toast_0"
Column | Type | Modifiers | Storage | Stats target | Description
--------+------+-----------+---------+--------------+-------------
info | text | | main | |

查看toast表的名字

dellstore2=# select relname,relfilenode,reltoastrelid from pg_class where relname = 'toast_0';
relname | relfilenode | reltoastrelid
---------+-------------+---------------
toast_0 | 16507 | 16510
(1 row) dellstore2=# select relname from pg_class where oid = 16510;
relname
----------------
pg_toast_16507
(1 row)

toast四种存储策略

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

toast表额外的三个字段

字段名 属性
chunk_id 标识TOAST表的OID字段
chunk_seq chunk的序列号,与chunk_id的组合唯一索引可以加速访问
chunk_data 存储TOAST表的实际数据
dellstore2=# select oid,relname,reltoastrelid from pg_class where relname = 'toast_0';
oid | relname | reltoastrelid
-------+---------+---------------
16507 | toast_0 | 16510
(1 row) dellstore2=# \d+ toast_0
Table "public.toast_0"
Column | Type | Modifiers | Storage | Stats target | Description
--------+------+-----------+---------+--------------+-------------
info | text | | main | |

toast表的计算

  • 计算一个表的大小时要注意统计toast的大小,因为对超长字段存储时,在基础表上可能只存了20%,另外的数据都存到了toast表里面去了,计算大小时要结合起来看
  • 索引也是一样,对于表里有extended或者EXTERNA类型的会创建toast表,两者的关联是通过pg_class里的OID取关联的
dellstore2=# create table toast_t(id int,name varchar(50),info text);
CREATE TABLE
dellstore2=# select relname,relfilenode,reltoastrelid from pg_class where relname = 'toast_t';
relname | relfilenode | reltoastrelid
---------+-------------+---------------
toast_t | 16513 | 16516
(1 row) dellstore2=# insert into toast_t select generate_series(1,2),'test',repeat('t',10000);
INSERT 0 2
dellstore2=# select pg_column_size(id),pg_column_size(name),pg_column_size(info) from toast_t;
pg_column_size | pg_column_size | pg_column_size
----------------+----------------+----------------
4 | 5 | 125
4 | 5 | 125
(2 rows) dellstore2=# select pg_size_pretty(pg_relation_size('toast_t')),pg_size_pretty(pg_relation_size(16516));
pg_size_pretty | pg_size_pretty
----------------+----------------
8192 bytes | 0 bytes
(1 row) dellstore2=# insert into toast_t select generate_series(1,2),'test',repeat('t',100000);
INSERT 0 2
dellstore2=# select pg_size_pretty(pg_relation_size('toast_t')),pg_size_pretty(pg_relation_size(16516));
pg_size_pretty | pg_size_pretty
----------------+----------------
8192 bytes | 0 bytes
(1 row) dellstore2=# insert into toast_t select generate_series(1,2),'test',repeat('t',200000);
INSERT 0 2
dellstore2=# select pg_size_pretty(pg_relation_size('toast_t')),pg_size_pretty(pg_relation_size(16516));
pg_size_pretty | pg_size_pretty
----------------+----------------
8192 bytes | 8192 bytes
(1 row) dellstore2=# insert into toast_t select generate_series(1,2),'test',repeat('t',400000);
INSERT 0 2
dellstore2=# select pg_size_pretty(pg_relation_size('toast_t')),pg_size_pretty(pg_relation_size(16516));
pg_size_pretty | pg_size_pretty
----------------+----------------
8192 bytes | 16 kB
(1 row)

可以看到后插入的数据随着字段内容的增多,toast段一直在变大。基础表的大小没有变化。

toast表的优点

  1. 可以存储超长大字段,避免之前不能直接存储的限制;
  2. 物理上与普通表是分离的,检索查询时不检索到该字段会极大地加快速度;
  3. 更新普通表时,该表地toast数据没有被更新时,不用去更新toast表

toast表的缺点

  1. 对大字段的索引创建是一个问题,有可能会失败,通常不建议在大字段上创建,全文检索是一个解决方案
  2. 大字段的更新会有点慢, 其他DB也存在相同问题

最新文章

  1. CSDN:你认为一名优秀的技术人应该具备怎样的素质?
  2. Ubuntu W: GPG error: http://archive.ubuntukey....NO_PUBKEY 8D5A09
  3. oracle 创建用户
  4. nginx 一二事(2) - 创建虚拟静态服务器
  5. MySQL各个版本区别
  6. C# List.sort排序详解(多权重,升序降序)
  7. Web服务器和动态语言如何交互--CGI&FastCGI&FPM浅谈
  8. JS代码放在head和body中的区别分析
  9. 知物由学 | 基于DNN的人脸识别中的反欺骗机制
  10. Go 编译原理实现计算器(测试驱动讲解)
  11. Html,CSS和盒子
  12. JDK源码分析(4)之 LinkedList 相关
  13. Oracle 查看链接数、创建索引等的DDL语句
  14. 【Java】 剑指offer(30) 包含min函数的栈
  15. jsp(待改)
  16. Struts2 REST 插件 XStream 远程代码执行漏洞 S2-052 复现过程
  17. javap 反汇编class文件
  18. 一篇来自网络的关于“enqueue”events的简短参考(转)
  19. vim正则表达式小结
  20. http://www.tangible-engineering.com/tangible_t4editor.html

热门文章

  1. 车牌识别服务-JAVA+ONNX版本,支持全类型的车牌
  2. 【分析笔记】Linux tasklet 机制的理解
  3. python开发简单的命令行工具
  4. python学习第二周总结
  5. clion添加ROS环境变量
  6. 微信小程序-【转发好友】以及中文标题乱码问题解决
  7. 【Go并发编程】Goroutine的基本使用
  8. P4238 【模板】多项式乘法逆
  9. JZOJ 2933. 【NOIP2012模拟8.7】找位置
  10. CentOS7加入AD域(winbind)