计算和保存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个字节的列最后不会出错。 text
或boolean
没有这样的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个字节的开销 。 另外,数组的元素像往常一样占用空间。 没有什么可以获得的。