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个字节的倍数对齐.
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');有关表和元组大小的更多信息.
相关回答:
每行都有与之关联的元数据。正确的公式是(假设天真对齐):
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来帮助解决这个确切用例的问题。您可能想查看类似的帖子以获取更多详细信息:元组开销。