了解Postgres行大小

时间:2012-11-26 18:08:35

标签: postgresql database-design types storage

我有一个大的(> 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)

2 个答案:

答案 0 :(得分:44)

行大小的计算要复杂得多。

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

还有更多的开销每行(元组):页面开头的4个字节的项标识符,23个字节的HeapTupleHeader 对齐填充 。元组头的开始以及元组数据的开始以MAXALIGN的倍数对齐,在典型的64位机器上为8字节。某些数据类型需要与下一个2个,4个或8个字节的倍数对齐。

Quoting the manual on the system table pg_tpye:

  

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

     

可能的值是:

     
      
  • c = char对齐,即无需对齐。

  •   
  • s = short路线(大多数机器上有2个字节)。

  •   
  • i = int对齐(大多数机器上为4个字节)。

  •   
  • d = double路线(许多机器上有8个字节,但绝不是全部)。

  •   

阅读手册here中的基础知识。

你的例子

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

加上占用4个字节的页眉中的每个元组的项标识符(如pointed out by @A.H. in the comment):

 +  4   -- item pointer 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');以获取有关表格和元组大小的更多信息。

相关:

答案 1 :(得分:3)

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

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

大约53个字节。我实际上写了postgresql-varint专门用来帮助解决这个问题。您可能需要查看similar post以获取更多详细信息:tuple overhead。