计算和保存PostgreSQL中的空间

我有一张桌子,像这样:

CREATE TABLE t ( a BIGSERIAL NOT NULL, -- 8 b b SMALLINT, -- 2 b c SMALLINT, -- 2 b d REAL, -- 4 b e REAL, -- 4 b f REAL, -- 4 b g INTEGER, -- 4 b h REAL, -- 4 b i REAL, -- 4 b j SMALLINT, -- 2 b k INTEGER, -- 4 b l INTEGER, -- 4 b m REAL, -- 4 b CONSTRAINT a_pkey PRIMARY KEY (a) ); 

以上每行最多可以有50个字节。 我的经验是我需要另外40%到50%的系统开销,甚至没有任何用户创build的索引到上面。 所以,每行大约75字节。 我将在桌子上有很多行,可能会有1450亿行,所以桌子将会推动13-14兆兆字节。 有什么办法可以用来压缩这张桌子? 我下面可能的想法…

real值转换为integer 。 如果它们可以存储为smallint ,那么每个字段可节省2个字节。

将列b .. m转换为数组。 我不需要在这些列上进行search,但是我确实需要能够一次返回一列的值。 所以,如果我需要列g,我可以做类似的事情

 SELECT a, arr[5] FROM t; 

我会用arrays选项节省空间吗? 会有速度惩罚吗?

任何其他的想法?

在数组中存储多个数字字段时,我看不出有什么可以获得的东西(以及丢失的东西)。

每个数字types的大小都有明确的logging,您应该简单地使用与您想要的范围分辨率兼容的最小尺寸的types; 这就是你所能做的一切

我不认为(但我不确定)如果有一些字节alignment要求列的行,在这种情况下重新排列的列可以改变使用的空间 – 但我不这么认为。

顺便说一句,每行有一个修复开销,大约23个字节 。

“俄罗斯方块”

其实,你可以做点什么 ,但这需要更深入的了解。 关键字是alignment填充 。 每种数据types都有特定的alignment要求 。

您可以通过顺序排列来最小化填充列之间的空间损失。 以下(极端)例子会浪费很多物理磁盘空间:

 CREATE TABLE t ( e int2 -- 6 bytes of padding after int2 , a int8 , f int2 -- 6 bytes of padding after int2 , b int8 , g int2 -- 6 bytes of padding after int2 , c int8 , h int2 -- 6 bytes of padding after int2 , d int8) 

要每行保存24个字节 ,请改用:

 CREATE TABLE t ( a int8 , b int8 , c int8 , d int8 , e int2 , f int2 , g int2 , h int2) -- 4 int2 occupy 8 byte (MAXALIGN), no padding at the end 

作为一个经验法则,如果你先放8个字节的列,那么4个字节,2个字节和1个字节的列最后不会出错。 textboolean没有这样的alignment限制,其他一些types。 有些types可以被压缩或“烤” (不符合保存)。

通常情况下,每行最多可以节省几个字节,最多可以播放“列俄罗斯方块” 。 在大多数情况下,这些都不是必要的。 但是拥有数十亿行,这可能意味着几千兆字节。

您可以使用函数pg_column_size()来testing实际的列/行大小。
请注意,某些数据types可以在RAM中使用比在磁盘(压缩格式)上更多的空间。 因此,当使用pg_column_size()testing相同的值(或行值与表行)时,可以得到比表列(磁盘格式)更大的常量(RAM格式)结果。

SQL小提琴。

每个元组的开销(行)

项目指针每行4个字节 – 不受上述考虑。
至less有24个字节(23 +填充)的元组头。 数据库页面布局手册:

有一个固定大小的标题(在大多数机器上占用23个字节),后面是一个可选的空位图,一个可选的对象标识字段和用户数据。

对于标题和用户数据之间的填充,您需要知道服务器上的MAXALIGN通常是64位操作系统上的8个字节(或32位操作系统上的4个字节)。 如果您不确定,请查看pg_controldata

在你的Postgres二进制目录中运行下面的命令来得到一个明确的答案:

 ./pg_controldata /path/to/my/dbcluster 

手册:

实际的用户数据(行的列)从t_hoff指定的偏移处开始,该偏移量必须始终为平台的MAXALIGN距离的倍数。

因此,通常通过以8个字节的倍数打包数据来获得最佳存储。

你发布例子中没有什么可以获得的。 它已经包装得很紧密。 最后一个int2之后的2个字节的填充,最后4个字节。 您可以在最后将填充合并为6个字节,这不会改变任何内容。

每个数据页面的开销

每个数据页面有一些开销(通常为8 KB):余数不足以容纳另一个元组,更重要的是死行或者使用FILLFACTOR设置保留的FILLFACTOR

考虑到磁盘大小还有其他一些因素:

  • 我可以在Heroku的5 MB PostgreSQL中存储多less条logging?
  • 在PostgreSQL中不使用NULL仍然在头中使用NULL位图?
  • configurationPostgreSQL的读取性能

数组types?

像你正在评估的数组 ,你可以单独为数组types添加24个字节的开销 。 另外,数组的元素像往常一样占用空间。 没有什么可以获得的。