gp堆表AO表、行存和列存

堆表AO表

1、堆表,实际上就是PG的堆存储,堆表的所有变更都会产生REDO,可以实现时间点恢复。但是堆表不能实现逻辑增量备份(因为表的任意一个数据块都有可能变更,不方便通过堆存储来记录位点。)。

一个事务结束时,通过clog以及REDO来实现它的可靠性。同时支持通过REDO来构建MIRROR节点实现数据冗余。

2、AO表,看名字就知道,只追加的存储,删除更新数据时,通过另一个BITMAP文件来标记被删除的行,通过bit以及偏移对齐来判定AO表上的某一行是否被删除。

事务结束时,需要调用FSYNC,记录最后一次写入对应的数据块的偏移。(并且这个数据块即使只有一条记录,下次再发起事务又会重新追加一个数据块)同时发送对应的数据块给MIRROR实现数据冗余。

因此AO表不适合小事务,因为每次事务结束都会FSYNC,同时事务结束后这个数据块即使有空余也不会被复用。(你可以测试一下,AO表单条提交的IO放大很严重)。

虽然如此,AO表非常适合OLAP场景,批量的数据写入,高压缩比,逻辑备份支持增量备份,因此每次记录备份到的偏移量即可。加上每次备份全量的BITMAP删除标记(很小)。

 

行存和列存的原理

1、行存,以行为形式组织存储,一行是一个tuple,存在一起。当需要读取某列时,需要将这列前面的所有列都进行deform,所以访问第一列和访问最后一列的成本实际上是不一样的。

在这篇文档中,有deform的详细介绍。《PostgreSQL 向量化执行插件(瓦片式实现) 10x提速OLAP》

行存小结:

全表扫描要扫描更多的数据块。

压缩比较低。

读取任意列的成本不一样,越靠后的列,成本越高。

不适合向量计算、JIT架构。(简单来说,就是不适合批处理形式的计算)

需要REWRITE表时,需要对全表进行REWRITE,例如加字段有默认值。

2、列存,以列为形式组织存储,每列对应一个或一批文件。读取任一列的成本是一样的,但是如果要读取多列,需要访问多个文件,访问的列越多,开销越大。

列存小结:

压缩比高。

仅仅支持AO存储(后面会将)。

读取任意列的成本是一样的。

非常适合向量计算、JIT架构。对大批量数据的访问和统计,效率更高。

读取很多列时,由于需要访问更多的文件,成本更高。例如查询明细。

需要REWRITE表时,不需要对全表操作,例如加字段有默认值,只是添加字段对应的那个文件。

什么时候选择行存

如果OLTP的需求偏多,例如经常需要查询表的明细(输出很多列),需要更多的更新和删除操作时。可以考虑行存。

什么时候选择列存

如果OLAP的需求偏多,经常需要对数据进行统计时,选择列存。

需要比较高的压缩比时,选择列存。

如果用户有混合需求,可以采用分区表,例如按时间维度的需求分区,近期的数据明细查询多,那就使用行存,对历史的数据统计需求多那就使用列存。

sql

CREATE TABLE table_xx(id int,n1 varchar,n2 varchar,n3 varchar)

WITH
(appendonly=
true
,orientation=
column
,compresstype=
zlib
,COMPRESSLEVEL=
5
)

distributed by (id);

①QuickLZ - 低压缩率、低cpu消耗、压缩数据块

②zlib - 高压缩率、低速

(注: QuickLZ的压缩级别只有level1,zlib能够设置从1-9)

建表的时候加上 with(appendonly=true) 就可以指定表是Appendonly表。如果需要建压缩表,则加上 with(appendonly=true,compresslevel=5),其中compresslevel是压缩率,取值为1~9,一般选择5就足够

appendonly=true, orientation=column这两个属性决定了这是列存压缩表。

compresstype: 压缩方式,支持zlip,rte等

compresslevel: 压缩级别,0-9,一般压缩级别为5即可

blocksize: 块大小8KB-2MB, 大小在8192 - 2097152 之间并且是8192的倍数

distributed by(fieldname1,fieldname2) : 分布键可以以多个设置,也可以设置一个,GP会hash分布到不同的segment上

 

posted @ 2021-09-26 10:19  foreast  阅读(1631)  评论(0编辑  收藏  举报