了解Postgres行大小

Arm*_*man 23 postgresql storage database-design types

我得到了一个大的(> 100M行)Postgres表,其结构为{integer,integer,integer,timestamp without time zone}.我期望一行的大小为3*整数+ 1*时间戳= 3*4 + 1*8 = 20字节.

实际上,行大小pg_relation_size(tbl) / count(*)= 52字节.为什么?

(不对表进行删除:pg_relation_size(tbl, 'fsm')〜= 0)

Erw*_*ter 46

行大小的计算比这复杂得多.

存储通常分为8 kb 数据页.每页有一个小的固定开销,可能的余数不足以容纳另一个元组,更重要的是死行或最初保留的FILLFACTOR设置百分比.

更重要的是,每行(元组)有开销.所述HeapTupleHeader的23个字节和对齐填充.元组头的开始以及元组数据的开始以多个对齐,MAXALIGN在典型的64位机器上为8个字节.某些数据类型需要与下一个2个,4个或8个字节的倍数对齐.

在系统表上引用手册pg_tpye:

typalign是存储此类型值时所需的对齐方式.它适用于磁盘上的存储以及PostgreSQL中值的大多数表示.当连续存储多个值时,例如在磁盘上的完整行的表示中,在此类型的数据之前插入填充,以便它在指定的边界上开始.对齐参考是序列中第一个数据的开头.

可能的值是:

  • c= char对齐,即不需要对齐.

  • s= shortalignment(大多数机器上的2个字节).

  • i= intalignment(大多数机器上的4个字节).

  • d= doublealignment(许多机器上的8个字节,但绝不是全部).

这里阅读手册中的基础知识.

你的榜样

这会在3 integer列之后产生4个字节的填充,因为该timestamp列需要double对齐并且需要从8个字节的下一个倍数开始.

所以,一行占用:

   23   -- heaptupleheader
 +  1   -- padding or NULL bitmap
 + 12   -- 3 * integer (no alignment padding here)
 +  4   -- padding after 3rd integer
 +  8   -- timestamp
 +  0   -- no padding since tuple ends at multiple of MAXALIGN
Run Code Online (Sandbox Code Playgroud)

最后,pg_relation_size(tbl) / count(*)页眉中的每个元组都有一个指针(项指针)(由注释中的@AH指出)占用4个字节:

 +  4   -- item pointer in page header
------
 = 52 bytes
Run Code Online (Sandbox Code Playgroud)

所以我们得到了观察到的52个字节.

计算pg_relation_size(tbl)是一个悲观的估计.fillfactor包括膨胀(死行)和保留的空间varlena,以及每个数据页和每个表的开销.(我们甚至没有提到TOAST表中长varlena数据的压缩,因为它不适用于此.)

您可以安装附加模块pgstattuple并调用SELECT * FROM pgstattuple('tbl_name');有关表和元组大小的更多信息.

相关回答:

  • 那么Postgres对于行很短的大表来说并不是那么好,例如.几个整数.28字节的开销总是会膨胀它.你知道Postgres在将它们保存在缓存中时是否会压缩这些表吗? (2认同)
  • 是不是每个块中还有一个额外的每行开销:`ItemData`指针(4字节)到实际的元组头? (2认同)
  • @Arman:RAM中的数据表示需要更多的空间.所以不,那里没有压缩.如果你有很长的字符串,它们会被压缩并可能被"烘烤".[更多关于这里手册中的"TOAST"](http://www.postgresql.org/docs/current/interactive/storage-toast.html).因此,非常小的元组有相当大的开销.尽管如此,对表格的操作通常非常快,所以不要因为过早地使表格非规范化的诱惑而陷入困境.如有疑问,请运行性能测试. (2认同)

Sea*_*ean 5

每行都有与之关联的元数据。正确的公式是(假设天真对齐):

3 * 4 + 1 * 8 == your data
24 bytes == row overhead
total size per row: 23 + 20
Run Code Online (Sandbox Code Playgroud)

或大约 53 个字节。实际上,我专门编写了postgresql-varint来帮助解决这个确切用例的问题。您可能想查看类似的帖子以获取更多详细信息:元组开销。