postgresql 理解Postgres行大小

noj0wjuj  于 12个月前  发布在  PostgreSQL
关注(0)|答案(2)|浏览(188)

我得到了一个结构为{integer,integer,integer,timestamp without time zone}的大(> 100 M行)Postgres表。我期望行的大小为3integer + 1timestamp = 34 + 18 = 20字节。
实际上行的大小是pg_relation_size(tbl) / count(*) = 52字节,为什么?
(No删除是针对表完成的:pg_relation_size(tbl, 'fsm') ~= 0)

bxjv4tth

bxjv4tth1#

行大小的计算要比这复杂得多。
存储通常以8 KB的数据页进行分区。每页有少量的固定开销,可能会有不足以容纳另一个元组的剩余部分,更重要的是,有死行或最初使用FILLFACTOR设置保留的百分比。
而且每行**(元组)的开销**也更多:在页的开始处的4个字节的项标识符、23个字节的HeapTupleHeader和 * 对齐填充 * 元组头部的开始以及元组数据的开始以MAXALIGN的倍数对齐,这在典型的64位机器上是8个字节。2某些数据类型需要与2、4或8字节的下一个倍数对齐。
Quoting the manual on the system table pg_type :
typalign是存储此类型的值时所需的对齐方式。它适用于磁盘上的存储以及PostgreSQL中的大多数值表示。当连续存储多个值时,例如在磁盘上以完整行的表示形式存储时,在此类型的基准面之前插入填充,使其从指定的边界开始。对齐参考是序列。
可能的值为:

  • c = char对齐,即不需要对齐。
  • s = short对齐(大多数计算机上为2个字节)。
  • i = int对齐方式(大多数计算机上为4个字节)。
  • d = double对齐(在许多机器上为8字节,但绝不是所有机器上都是8字节)。

阅读有关basics in the manual的信息。

你的例子

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

字符串
加上页眉中每个元组的项标识符(如注解中@A.H.所指出的):

+  4   -- item identifier in page header
------
 = 52 bytes


因此,我们得到了观察到的52字节
pg_relation_size(tbl) / count(*)的计算是一个悲观的估计。pg_relation_size(tbl)包括膨胀(死行)和fillfactor保留的空间,以及每个数据页和每个表的开销。(我们甚至没有提到在TOAST tables中对长varlena数据的压缩,因为它在这里不适用。)
您可以安装额外的模块pgstattuple并调用SELECT * FROM pgstattuple('tbl_name');,以获取有关表和元组大小的更多信息。
相关信息:

  • 表格大小与页面布局
  • PostgreSQL中的计算和节省空间
c6ubokkw

c6ubokkw2#

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

3 * 4 + 1 * 8 == your data
24 bytes == row overhead
total size per row: 23 + 20

字符串
或者大约53个字节。实际上我专门写了postgresql-varint来帮助解决这个问题。你可能想看看similar post来了解更多关于re:tuple开销的细节。

相关问题