理解Postgres行的大小
我得到了一个大(> 100M行)Postgres表结构{整数,整数,整数,没有时区的时间戳}。 我预计一个行的大小为3 *整数+ 1 *时间戳= 3 * 4 + 1 * 8 = 20个字节。
实际上,行大小是pg_relation_size(tbl) / count(*)
= 52个字节。 为什么?
(不对表执行删除操作: pg_relation_size(tbl, 'fsm')
〜= 0)
行大小的计算要比这复杂得多。
存储通常分为8 kb的数据页面 。 每页有一个小的固定开销,可能的余数不够大,不适合另一个元组,更重要的是死行或最初用FILLFACTOR
设置保留的FILLFACTOR
。
更重要的是, 每行 (元组)有开销。 23字节的HeapTupleHeader
和alignment填充 。 元组头的开始以及元组数据的开始以MAXALIGN
的倍数alignment,这是一个典型的64位机器上的8个字节。 某些数据types需要alignment到2,4或8个字节的下一个倍数。
引用系统表中的手册pg_tpye
:
typalign
是存储此types的值时所需的alignment方式。 它适用于磁盘上的存储以及PostgreSQL中的大多数表示forms。 当连续存储多个值时(例如在磁盘上的完整行的表示forms中),将在此types的数据之前插入填充,以便在指定的边界上开始填充。 alignment引用是序列中第一个数据的开始。可能的值是:
c
=char
alignment,即不需要alignment。
s
=short
alignment(大多数机器上2个字节)。
i
=int
alignment(大多数机器上4个字节)。
d
=double
alignment(在许多机器上是8个字节,但不是全部)。
阅读手册中的基础知识。
你的例子
这将导致在3个integer
列之后填充4个字节,因为timestamp
列需要double
alignment,并且需要从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
最后,页眉中每个元组都有一个ItemData
指针(项目指针),它占用4个字节:
+ 4 -- item pointer in page header ------ = 52 bytes
所以我们到达了观察到的52个字节 。
计算pg_relation_size(tbl) / count(*)
是一个悲观估计。 pg_relation_size(tbl)
包括bloat(死行)和由fillfactor
保留的空间,以及每个数据页和每个表的开销。 (我们甚至没有提到TOAST表中的长varlena数据的压缩,因为这里不适用。)
您可以安装附加模块pgstattuple并调用SELECT * FROM pgstattuple('tbl_name');
有关表和元组大小的更多信息。
相关解答:
- 表格大小与页面布局
每行都有与之关联的元数据。 正确的公式是(假设naievealignment):
3 * 4 + 1 * 8 == your data 24 bytes == row overhead total size per row: 23 + 20
或大致53个字节。 我实际上编写了postgresql-varint来帮助解决这个问题。 你可能想看看类似的post,了解更多的细节:元组开销。