PostgreSQL的TOAST技术

2020-06-17 00:00:00 数据 字段 压缩 长度 外存

本文参考:

  • 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的长度值都表示数据的实际尺寸,而不是压缩后的长度。

在 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 |              |

相关文章