Greenplum AO列存储设计解析

解析背景:

Greenplum AO列存,主要面向OLAP场景。表的列很多,分析其中少部分列,通过AO列存方式,大块的IO读,降低IO成本,提升分析速度。AO以前是appendonly,不支持update/delete,后来支持了,内部也改叫append optimized表。

一、AO列表存储设计

一张AO列存表主要涉及到表有pg_appendonly、pg_aoseg_<relid>、pg_aoblkdir_<relid>、pg_aovisimap_<relid>,这些表归属于pg_aoseg空间。

1. 表定义

pg_appendonly

存放该AO表额外的一些元数据,可以当作pg_class的扩展表。

字段名类型描述
relidoid表的唯一标识,和pg_class中这张表对应的oid字段相同
blocksizeintegerao表的块大小,默认32 k
safefswritesizeinteger最小安全写入数据块大小
compresslevelsmallint压缩率
checksumboolean是否校验。创建一个块的对应校验码,读取时进行校验,保证数据的一致性
compresstypename压缩类型
columnstoreboolean1:列存,0:行存
segrelidoidpg_aocsseg_<relid>表对应的oid
blkdirrelidoidpg_aoblkdir_< relid >表对应的oid
blkdiridxidoidpg_aoblkdir_< relid >表索引对应的oid
visimaprelidoidpg_aovisimap_< relid >表对应的oid
visimapidxidoidpg_aovisimap_< relid >表索引对应的oid

参考链接: https://gpdb.docs.pivotal.io/6-11/ref_guide/system_catalogs/pg_appendonly.html

pg_aocsseg_< relid >

存放AO表所属的segment文件的元数据信息。

字段名类型描述
segnointeger段号
tupcountbigint元组数
varblockcountbigint元组占用的块数
vpinfobyteaSeg文件大小信息相关。如eof:文件有效的结尾;eof_uncompressd:没有压缩文件的文件结尾
modcountbigint表被操作的次数
formatversionsmallint版本信息
statesmallint文件状态

参考链接:https://gpdb.docs.pivotal.io/6-11/ref_guide/gp_toolkit.html

pg_aoblkdir_<relid>

存放AO表的元组行号和文件块关系的元数据信息。

字段名类型描述
segnointeger段号
columngroup_nointeger列号
first_row_nobigint元组首行号
minipagebytea块页面摘要

pg_ aovisimap _<relid>

字段名类型描述
segnointeger段号
first_row_nobigint元组首行号
visimapvisimap采用位图方式标记元组的删除和修改信息

2. 关键字段说明

AOTupleId

AOTupleId(TID)是元组的唯一标识,格式为(segfile#,row#)。数据结构如下:

结构定义说明
typedef struct AOTupleId {   uint16 bytes_0_1;   uint16 bytes_2_3;   uint16 bytes_4_5; }前7个bit定义segno 再用25个bit存放行号 剩余16个bit作为保留位 对于heap表,前32位含义blockno+rownum,唯一定位元组位置。为了保证兼容,AO表和heap表的所占用位数一致 最后两字节,heap表为offset且大于0;为了兼容,AO表做了加1的操作

更多信息参看gpdb项目:/src/include/access/appendonlytid.h中AOTupleId和/src/include/storage/itemptr.h中ItemPointerData。

minipage

minipage是的数据块摘要信息,存放在pg_aoblkdir_<relid>表,当AO列表创建索引就会生成辅组表pg_aoblkdir_<relid>。基于索引扫描,key找到对应的TID(segno,rownum),然后通过rownum从minipage中快速定位数据所在的block,最后从block中读取元组数据。

数据结构如下:

结构定义说明
typedef struct d {   int32 _len;   int32 version;   uint32 nEntry;//Minipage个数   MinipageEntry entry[1]; }minipage typedef struct MinipageEntry {   int64 firstRowNum;//首行   int64 fileoffset;//文件中的偏移   int64 rowCount;//块中元组数   } MinipageEntry采用block方式写元组数据,每次写对应生成Minipage数据 数据结构定义,参看/src/include/cdb/cdbappendonlyblockdirectory.h TID的rownum定位Minipage 采用的是二分查找法。更多信息参看/src/backend/access/appendonly/appendonlyblockdirectory.c中find_minipage_entry函数

二、实验探索

为了简化过程,这里以utility模式登录其中的一个segment库。Greenplum版本信息如下: 

1. 登录SegmentDB

(注:不同的环境端口号可能不同,这里登录端口号为6005的SegmentDB)

2. 创建col_table列存表

create table col_table(c1 int,c2 varchar) with(appendonly=true,orientation=column);

3. 查看pg_class

select oid,relname,relfilenode from pg_class where relname='col_table';
  • oid(16387):col_table的唯一标识
  • relfilenode(16385):操作系统中对应的物理文件名。

如下所示:

4. 查看pg_appendonly

  • blocksize(32768):块大小32k。
  • segrelid(16392):pg_aoseg_< relid >表的oid。
  • blkdirrelid(0):pg_aoblkdir_<relid>表的oid。当前表无索引,因而为0。
  • visimaprelid(16394):pg_aovisimap_<relid>表的oid。

5. 创建索引

create index col_table_idx on col_table(c1);

再次查看pg_appendonly表,blkdirrelid发生变化。如下图:

6. pg_class查看辅组表信息

辅组表名称

select oid,relname,relfilenode from pg_class 
where oid in(16387,16392,16398,16400,16394,16396);

追加col_table元组

这里的ctid为(0,2),为什么不是(0,1)?AOTupleId为了兼容heap表的TID,做了加1操作。

再次追加col_table元组

新的元组ctid(0,202),为什么不是(0,3)?因为每个block缺省的seqnum=100,每次block操作元组rownum至少增加100。

7. 辅组表内容查看

再追加一条记录辅组表的信息会发生对应变更。

8. 操作系统文件查看

删除SegmentDB的col_table

通过master建表

  • 并发追加元组
  • 数据文件
  1. 看到4个文件,16400.1和16400.129对应一个事务操作;16400.2和16400.130对应另一个事务操作;16400.1和16400.2对应第一列;16400.129和16400.130对应第二列。
  2. AOTupleId中用7个bit表示段号,所以可以支持128个并发对AO列存表同时追加元组的操作。

 

总结

AO列存优点分析速度快,对于OLAP场景,每次分析涉及的字段较少,采用GP的AO表的这个设计可以保证行级严格事务,这在列存数据库中不多见,这样的设计有利于高吞吐数据量的加载。同时通过块的方式提高数据的压缩比。
ao列存缺点每个列至少对应一个文件。例如集群有10个primary,10个mirror,一张有500列按天分区的列表,对应年的文件数>(10+10)*365*500=3650000。因而需要结合数据量和查询特征来设计合理的segment和分区的个数。 GP5、GP6存储空间占用大,如果表建索引,频繁的小批量加载数据会导致pg_aoblkdir_<relid>占用非常大的存储空间。GP7有brin索引可以考虑,索引文件会非常小,小到可以忽略不计。

本文介绍AO列存辅组表,以及相关设计进行解读,为更好的使用和理解AO列存表提供帮助,用户需要根据业务场景选择是否要采用AO列存。

三、参考链接

作者:王爱军
20年来一直工作在一线的老码农,目前就职于中兴通讯。主要工作方向为5G网络管理系统架构,近期在使用和研究Greenplum。

关注微信公众号

VMware 中国研发中心

Greenplum官方技术交流群

扫码添加小助手即可入群,添加时请备注 “GP网站”