其他分享
首页 > 其他分享> > Greenplum性能优化之路 --(二)存储格式

Greenplum性能优化之路 --(二)存储格式

作者:互联网

存储格式介绍

Greenplum(以下简称GP)有2种存储格式,Heap表和AO表(AORO表,AOCO表)。

Heap表

Heap表是从PostgreSQL继承而来,使用MVCC来实现一致性。如果你在创建表的时候没有指定任何存储格式,那么GP就会使用Heap表。

Heap表支持分区表,只支持行存,不支持列存和压缩。需要注意的是在处理update和delete的时候,Heap表并没有真正删除数据,而只是依靠version信息屏蔽老的数据,因此如果你的表有大量的update或者delete,表占用的物理空间会不断增大,这个时候需要依靠vacuum来清理老数据。

Heap表不支持逻辑增量备份,因此如果要对Heap表做快照,每次都需要导出全量数据。

建表语句

CREATE TABLE heap(
	a int,
	b varchar(32)
) DISTRIBUTED BY (a);

最佳实践:

AO表

AO表是GP特有的,设计的目的就是为了数仓中大型的事实表。AO表支持行存和列存,并且也支持对数据进行压缩。

AO表无论是在表的逻辑结构还是物理结构上,都与Heap表有很大的不同。比如上文所述Heap表使用MVCC控制update和delete之后数据的可见性,而AO表则使用一个附加的bitmap表来实现,这个表的的内容就是表示AO表中哪些数据是可见的。

对于有大量update和delete的AO表,同样需要vacuum进行维护,不过在AO表中,vacuum需要对bitmap进行重置并压缩物理文件,因此通常比Heap的vacuum要慢。

AORO表

AORO就是行存的AO表,同时行存也是AO表的默认存储方式。

AORO支持表级别的压缩,不支持列级别的压缩。

建表语句如下,重点是with后的appendonly=true,由于AO表默认是行存,因此orientation=row也可以不要,后面的compresstype=zlib, compresslevel=4都是压缩相关选项。

CREATE TABLE aoro(
	a int,
	b int,
	c varchar(32),
	d varchar(32)
)
WITH (appendonly=true, orientation=row, compresstype=zlib, compresslevel=4)
DISTRIBUTED BY (a)

压缩选项:

最佳实践____________________:

AOCO表

AOCO表就是列存的AO表。

AOCO不仅支持表级别的压缩,同时也支持列级别的压缩。

建表语句如下,这里还加入了分区特性,关于分区可以参见Greenplum性能优化之路 --(一)分区表

CREATE TABLE aoco(
	a int  ENCODING (compresstype=zlib, compresslevel=5),
	b int  ENCODING (compresstype=none),
	c varchar(32) ENCODING (compresstype=RLE_TYPE, blocksize=32768),
	d varchar(32),
	fdate date
)
WITH (appendonly=true, orientation=column, compresstype=zlib, compresslevel=6, blocksize=65536)
DISTRIBUTED BY (a)
PARTITION BY RANGE(fdate) 
(
	PARTITION pn START ('2018-11-01'::date) END ('2018-11-10'::date) EVERY ('1 day'::interval),
	DEFAULT PARTITION pdefault
);

压缩选项:

BLOCKSIZE:

物理文件:

最佳实践:

修改表结构

单独列出这一节是因为Heap,AORO和AOCO这3种表在修改表结构时表现是不一样的,这也是大家容易忽视的地方。

对于不同的表类型,同样的修改语法耗时可能会差异很多,主要原因在于对于有些修改操作会导致表重写,而表重写的时间就取决于表本身的数据量。

以下列出了不同的表结构,在不同的ALTER语法下的行为,其中YES代表需要重写表,NO代表不需要重写表。

操作

Heap

AORO

AOCO

ADD COLUMN

NO

YES

NO

DROP COLUMN

NO

NO

NO

ALTER COLUMN TYPE

YES

YES

YES

ADD COLUMN DEFAULT NULL

YES

YES

NO

ADD COLUMN DEFAULT VALUE

YES

YES

NO

可以看出AOCO表由于每个列都是单独一个文件,因此在修改列结构时影响最小,这也是AOCO表的一个优势。

混合存储

一张表是否可以同时使用多种存储方式呢?对于分区表,是可以的。

混合存储一般用于这样的场景,对于一张按时间分区的表,通常对于不同时间点的数据行为是不一样的,比如对于最近的数据,会有较多的明细查询,而对于比较老的数据,则是以分析为主。同时由于业务可能要保存较长时间的数据,为了节约成本,较老的数据会考虑使用压缩比较大的存储方式。

混合存储的关键就是使用到了GP的交换分区语法,也就是将一张独立的表与自己的一个分区表进行交换,当然这里前提是新表的结构是一样,并且交换的过程没有新数据进入。

流程如下:

1.创建一张分区表(1到5月份,每月一张表),采用Heap存储

CREATE TABLE hyper_storage (
	a int,
	b varchar(32),
	fdate date
) DISTRIBUTED BY (a)
PARTITION BY RANGE(fdate) 
(
	PARTITION pn START ('2018-01-01'::date) END ('2018-06-01'::date) EVERY ('1 month'::interval),
	DEFAULT PARTITION pdefault
);

storage=# \d
                           List of relations
 Schema |             Name             | Type  |    Owner     | Storage 
--------+------------------------------+-------+--------------+---------
 public | hyper_storage                | table | test | heap
 public | hyper_storage_1_prt_pdefault | table | test | heap
 public | hyper_storage_1_prt_pn_1     | table | test | heap
 public | hyper_storage_1_prt_pn_2     | table | test | heap
 public | hyper_storage_1_prt_pn_3     | table | test | heap
 public | hyper_storage_1_prt_pn_4     | table | test | heap
 public | hyper_storage_1_prt_pn_5     | table | test | heap

2.现在要对1月份的表修改存储格式,因此创建一张新的AOCO表

CREATE TABLE exchange_table(
	a int,
	b varchar(32),
	fdate date
) WITH (appendonly=true, ORIENTATION=column, compresstype=zlib, compresslevel=6) 
DISTRIBUTED BY (a)

3.将1月份的数据导入新表

INSERT INTO exchange_table SELECT * FROM hyper_storage_1_prt_pn_1;

4.交换分区

ALTER TABLE hyper_storage EXCHANGE PARTITION pn_1 WITH TABLE exchange_table;

注:pn_1是1月份的分区表的partitionname,可以从pg_partitions中查询得到

5.查看结果

storage=# \d
                                  List of relations
 Schema |             Name             | Type  |    Owner     |       Storage        
--------+------------------------------+-------+--------------+----------------------
 public | hyper_storage                | table | test | heap
 public | hyper_storage_1_prt_pdefault | table | test | heap
 public | hyper_storage_1_prt_pn_1     | table | test | append only columnar
 public | hyper_storage_1_prt_pn_2     | table | test | heap
 public | hyper_storage_1_prt_pn_3     | table | test | heap
 public | hyper_storage_1_prt_pn_4     | table | test | heap
 public | hyper_storage_1_prt_pn_5     | table | test | heap
public | exchange_table  | table | test | heap

这样1月份的分区表就变成了AOCO表,而其他分区表仍然是Heap表

对比测试

各类型表占用空间比较

选取Heap,AORO,AOCO三种表,分别采用压缩和不压缩2种方式(Heap表不支持压缩,AO表压缩采用zlib格式,压缩级别设置为6),插入5亿条随机数据,然后使用

select pg_size_pretty(pg_relation_size('{tablename}'));

查看表所占大小,结果如下:

 

各类型表大小比较.png

说明:可以看出Heap表占用空间更大,即使AO表不采用压缩。AOCO表由于是按列进行存储,所以相比行存的AORO表压缩比更大。当然这三者的差距取决于数据的实际情况,一般生产环境中Heap表不会和AO表有如此大的差距。

各级别压缩率比较

使用AOCO表,zlib压缩格式,选取不同的压缩级别,比较数据写入时间和表所占大小,由于zlib支持9个级别,这里选取1,6,9 三个级别进行比较,体现出趋势即可,结果如下:

各压缩级别比较.png

说明:实际生产环境中不同压缩级别的数据,压缩比的差距可能会更大。但可以看出,越高的压缩级别,在插入的时候越耗时,其它SQL,类似SELECT,UPDATE等也都是一样。

写在最后

切记,从其它系统迁移数据到GP上来,第一件事情就是给每张表选择合适的存储格式,特别是核心表

标签:--,Greenplum,storage,AO,Heap,table,格式,压缩,AOCO
来源: https://blog.csdn.net/jc_benben/article/details/118629392