|
我在pg其中一个表格如下所示:9 }& V, m% U- B
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%系统费用,甚至没有用户创建的上述索引。因此,每行大约有75个字节。表中会有很多行,可能超过1450亿行,所以表会推13-14 TB。我能用什么技巧来压缩这张桌子?我下面可能的想法…" D4 o1 j8 W% k. o8 g7 e2 ^
将real值转换为integer。若能储存为smallint,则每个字段节省2个字节。- } K8 t) Y$ H
将b .. m列转换为数组。我不需要搜索这些列,但我确实需要能够一次返回一个列的值。所以,如果我需要的话g列,我可以做类似的事情
4 l! B& R0 \* L0 w& SSELECT a,arr[5] FROM t;我可以使用array节省空间的选项?会有速度限制吗?
4 x) J! e% j" m- n3 d7 l. _还有别的想法吗?! \* i6 H8 \2 ]/ D. X; I
: d' M$ H0 |6 d& X5 `1 D% x* P$ P
解决方案:
: T* S* @6 i% l 事实上,你可以做一些事情,但这需要更深入的理解。关键词是alignment padding。每种数据类型都有特定的对齐要求。% a. o/ `0 b. G& k( R3 y) F
通过对列进行有序排序,可以最大限度地减少列之间填充损失的空间。以下(极端)示例将浪费大量物理磁盘空间:2 {7 @( a& d8 p. z% F/ i, u0 ^
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 enddb fiddle here旧的sqlfiddle
; z9 @( B6 `/ \6 ?根据经验,如果你先8字节列,再放4字节、2字节、1字节列,就不会出错。
# J, Y( {9 M( f7 m# I! Iboolean,uuid(!)不需要与其他类型对齐填充。text,varchar等“varlena名义上需要(可变长度)类型INT对齐(大多数机器都有四个字节)。但我没有观察到磁盘格式的对齐填充(与RAM不同)。最后,我在源代码注释中找到了解释:# n6 I1 _2 D( p3 ~, n
还请注意,在存储“打包”的varlenas我们将违反标称对齐;TOAST该机制负责将其隐藏在大多数代码中。
8 Q- @7 x1 c: {7 ?5 c因此,只有当单个前导长度字节(可能是压缩)数据超过127个字节时,才能强制执行 int对齐。varlena存储切换到四个前导字节,并要求 int”对齐。
$ C% V4 U' i; h# M. H& _5 Y9 p通常,最好在播放 cote tetris每行可以节省几个字节。在大多数情况下,这些都是不必要的。然而,随着数十亿行的出现,它可能很容易意味着数千兆字节。% S$ d: j, B: K: f: D, A) m
您可以使用函数测试实际列/行大小pg_column_size()。
8 @( d% ^3 Z# x+ Q$ c某些类型在RAM中比在磁盘上占用更多的空间(压缩或包装格式)。当用于测试相同值(或值的行和表的行)时,与表列相比,常量(RAM格式)可以获得更大的结果pg_column_size()。& k4 a- l0 |' {8 _2 }
最后,有些类型可以压缩或烘烤(存储在行外)或两者兼而有之。( u; p: y. `' m2 n" E% a' B" I
每个元组的费用(行); _& w/ [* c; [2 W6 T; j
项目标识符每行4字节-不考虑上述考虑。" g7 }8 x9 U# @* ]" \4 X
元组标头应至少有24个字节(23 填充)。关于数据库页面布局的手册:; O( B. X% f Y# w+ A5 w
有一个固定尺寸的标头(占大多数计算机的23个字节),然后是可选的空位图和可选对象ID字段和用户数据。
& G5 G. a" J$ `) }) a) Q: E+ f对于标头和用户数据之间的填充,您需要MAXALIGN了解服务器-在64位OS通常是8个字节(32位)OS上面是四个字节。如果不确定,请签字pg_controldata。
9 R* H @1 t4 T0 ^9 ^% @5 d在您的Postgres以下命令在二进制目录中运行以获得明确答案:
7 Z9 v6 U# m8 o/ p I# e- @ c./pg_controldata /path/to/my/dbcluster手册:
5 s% T5 w( x; G0 K6 j4 F实际用户数据(行列)从表示的偏移量开始,t_hoff必须始终是MAXALIGN 平台距离倍数。: E' s! d! C; P6 C% Z& X, B" x4 ^
因此,最佳存储效果通常通过打包8字节的倍数来获得。/ C) f9 M. k% E2 P# `' t
你发布的例子没有任何好处。它已经收紧了。int2.最后填写两个字节,最后填写四个字节。您可以将将填充合并为6个字节,不会改变任何内容。 |
|