我得到了一个结构为{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)
我得到了一个结构为{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)
2条答案
按热度按时间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字节的倍数开始。因此,一行占用:
字符串
加上页眉中每个元组的项标识符(如注解中@A.H.所指出的):
型
因此,我们得到了观察到的52字节。
pg_relation_size(tbl) / count(*)
的计算是一个悲观的估计。pg_relation_size(tbl)
包括膨胀(死行)和fillfactor
保留的空间,以及每个数据页和每个表的开销。(我们甚至没有提到在TOAST tables中对长varlena
数据的压缩,因为它在这里不适用。)您可以安装额外的模块pgstattuple并调用
SELECT * FROM pgstattuple('tbl_name');
,以获取有关表和元组大小的更多信息。相关信息:
c6ubokkw2#
每一行都有与之关联的元数据。正确的公式是(假设简单对齐):
字符串
或者大约53个字节。实际上我专门写了postgresql-varint来帮助解决这个问题。你可能想看看similar post来了解更多关于re:tuple开销的细节。