I got a large (>100M rows) Postgres table with structure {integer, integer, integer, timestamp without time zone}. I expected the size of a row to be 3*integer + 1*timestamp = 3*4 + 1*8 = 20 bytes.

实际上,行大小是pg_relation_size(tbl) / count(*)=52字节.为什么?

(没有对表进行删除:pg_relation_size(tbl, 'fsm')~=0)

推荐答案

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

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

还有更大的开销per row(元组):页面开头的项标识符为4字节,HeapTupleHeader为23字节,alignment paddingalignment padding字节.元组头的开头和元组数据的开头以MAXALIGN的倍数对齐,在典型的64位机器上是8字节.有些数据类型需要与下一个2、4或8字节的倍数对齐.

Quoting the manual on the system table pg_tpye:

typalign是存储此类型的值时所需的对齐方式.

可能的值包括:

  • c=char对齐,即不需要对齐.

  • s=short对齐(大多数机器上为2字节).

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

  • d=double对齐(许多机器上有8个字节,但决不是全部).

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

你的例子

这会在3integer列之后产生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

加上页面标题中每个元组的项标识符(如pointed out by @A.H. in the comment):

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

所以我们得出了观察到的52 bytes.

计算pg_relation_size(tbl) / count(*)是一个悲观的估计.pg_relation_size(tbl)包括inflating (死行)和fillfactor保留的空间,以及每个数据页和每个表的开销.(我们甚至没有提到对TOAST tables个长varlena个数据的压缩,因为它不适用于这里.)

您可以安装附加模块pgstattuple,并致电SELECT * FROM pgstattuple('tbl_name');以获取有关表和元组大小的更多信息.

相关的:

Postgresql相关问答推荐

PostgreSQL:`row_alias为null`且`row_alias不是null`返回值不一致

可以向判断枚举值的SQL列添加约束吗?

将列类型从文本[]更改为jsonb[]

将XML解析从T-SQL迁移到Postgres时出现问题

在Axum 0.5中,如何在一个请求处理程序中同时使用数据库和路径解析?

即使存在 GIN 索引,整理默认的类似查询也无法执行

PG 16 的 AGE 安装抛出错误:无法创建 src/backend/parser/ag_scanner.c

pgadmin db 限制服务器属性不起作用

使用 Heroku CLI、Postgres 的 SQL 语法错误

Postgres 会话处于空闲状态,query = COMMIT 或 ROLLBACK

PostgreSQL 提示:You will need to rewrite or cast the expression. column "state" is of type status but expression is of type character varying

查询仅属于特定部门的用户

在 PostgreSQL 中的表上禁用 DELETE?

无法在 postgresql hibernate 中使用名为user的表

如何将表的一列复制到PostgreSQL中比较相同ID的另一表的列

如何在Postgres中分组并返回总和行

Postgresql:备份所有表 struct ,但只备份少数数据表

在 Windows 7 上更改/重置 postgresql 用户密码

如何使用 PostgreSQL 在任何列中查找所有具有 NULL 值的行

如何在postgres中将整数分钟转换为间隔