序言
Greenplum(以下简称 GP)是一种基于开源PostgreSQL根底上采纳MPP架构的关系型分布式数据库,具备弱小的大规模数据分析解决能力。
GP有两种存储格局:Heap表和AO表。其中,AO表是Greenplum所特有的,次要面向OLAP场景,反对行存和列存,批量的数据写入,有利于高吞吐数据量的加载,同时反对对数据进行压缩,AOCO不仅反对表级别的压缩,同时也反对列级别的压缩。
GP-AO表的剖析速度快,对于OLAP场景,每次剖析波及的字段较少,能够保障行级严格事务。这种设计对大批量数据的拜访和统计需要而言,可能无效晋升剖析速度。
在近期的直播中,HashData内核研发工程师介绍了GP-AO表的设计和特点。以下内容依据直播文字整顿。
存储引擎概要
Heap表是从PostgreSQL继承而来的,目前是 GP 默认的表存储格局,只反对行存储,不反对列存和压缩。
Heap页面存储的数据称为元组(Tuple),在物理文件上不依照某种程序进行排序。当读取Heap文件页面时,也不会对元组的排序做任何假如。Heap的存储格局对于OLTP和OLAP两个拜访模式都是比拟无效的,但更适宜OLTP的场景,比方插入新的元组不须要思考元组间的互相程序,而且删除和更新元组也非常简单。
在OLAP的场景下,查问更多的是全表扫描。通常状况下,查问语句并不会读取所有列的数据,而会筛选出感兴趣的列。因为元组是将所有列都寄存在一块,这样会减少额定的IO开销。此外,Heap因为采纳跨页存储,检索非常复杂,对数据的压缩也不如AO和AOCS,对存储的开销较大。
总体来讲,Heap表的设计理念重视平衡性,对于元组增删查改的利用场景反对比拟平衡。存储

引擎的AO表设计
在OLAP的场景下,数据大多是一些历史数据或日志数据,个别不会批改或者仅大量批改,元组更多以追加而非批改的形式寄存。
另外,从数据拜访形式来看,OLAP须要读取大量记录,记录多以扫描的形式进行读取。同时,因为每个页面存在空洞或者曾经被删除的有效数据,扫描拜访形式对于Heap来说并不高效。
基于此,Greenplum引入了AO表,用来专门存储以追加形式插入的元组。最开始设计时,AO表被称为Append Only表,只反对追加新元组。在起初的演进中,也反对了删除和更新元组操作,因而当初AO表指的是Append Optimized。
与Heap表相比,AO表存储更紧凑,记录之间没有空余空间,在AO表上进行剖析通常效率更高。此外,AO表能够反对列式存储,在解决大批量数据时具备显著劣势,非常适合向量计算和JIT架构。
对于AO表的每个文件,元组总是增加到文件开端,所以文件的结尾地址(EOF)就能够作为数据可见性判断的根据。只有当事务胜利提交后,从原来EOF之后新追加的元组才对外可见,否则对外只能看到文件原来的EOF。
对此,Greenplum中提供了两个零碎表记录相应的信息:pg_appendonly和pg_aoseg.pg_aoseg_。其中,pg_appendonly表中segrelid记录了AO表所对应pg_aoseg.pg_aoseg_表的OID。
pg_aoseg.pg_aoseg_为Heap表,记录了AO表每个数据文件的EOF。这样能够通过MVCC来治理pg_aoseg.pg_aoseg_表中的EOF信息。
pg_aoseg.pg_aoseg_中的OID指的是AO表的OID。
另外,Heap的元组存储了太多可见性相干的信息,因为EOF曾经能够作为可见性判断的根据,所以AO表中存储的元组不须要存储这些额定的信息。
二者比照而言,AO表存储的元组构造是MemTuple,Heap假如的拜访场景是随机和程序拜访,AO表假如的拜访场景多是程序扫描;Heap表的块必须要大小统一,便于随机寻址,AO表的块并不需要定长存储,能够进行变长压缩,以节俭空间。
Heap表的块多个过程间须要共享,通过共享缓冲区进行治理。AO表因为是变长块,而且多是程序扫描,所以不通过共享缓冲区。
为了反对删除操作,AO表引入了VisibilityMap。如果元组被删除,将会在VisibilityMap中标记。该VisibilityMap信息由零碎表pg_aovisimap_保留。AO表的更新操作的实现也就转换为删除操作+插入操作。
因为AO表采纳的是变长块,无奈通过文件内的逻辑块号或行号间接定位到物理地位,然而为了反对在AO表上建设索引,须要通过行号疾速定位到物理地位以便进行元组读取。当AO表上建有索引时,Greenplum中会创立零碎表pg_aoblkdir_来存储行号到物理地位的映射信息,来缩小额定的存储开销。

AO表设计框架结构总体概况
数据设计
AO表的数据设计实现面对的次要问题是数据的增删改查,这就须要解决四个问题:数据寄存、数据可见性、数据表结构设计以及数据如何定位的实现。
其中,对于变长记录在数据库系统中的呈现有几个起因。最常见的起因是变长域的呈现,比方字符串。实现变长记录能够采纳不同的技术,但都必须解决两个问题:
1、如何示意单条记录,使得此记录的单个属性可能被轻松地提取,即便这些属性是变长的;
2、如何在一个块中存储变长的记录,使得一个块中的记录可能被轻松地提取。
具备变长属性的记录示意通常蕴含两个局部:首先是带有定长信息的初始局部,其构造对于雷同关系的所有记录都是一样的。紧接着是变长属性的内容,诸如数字值、日期或定长字符串等固定长度的属性,被调配存储它们的值所需的字节数。对于可变长字符串类型这类的变长属性,在记录的初始局部中被示意为一个(偏移量,长度)。
对于块中变长记录的存储问题,比方分槽的页构造,个别用于在块中组织记录,每个块开始有块头,蕴含如下信息:块头的记录项的数量、块中的自由空间的开端处、一个蕴含每条记录的地位和大小的项组成的数组。

数据寄存设计
AO表通过EOF来管制可见性,相比于HeapTuple,元组中不再须要存储可见性相干信息。MemTuple除了可用在AO表存储格局之外,还会用在执行器中,因为当元组从磁盘读取出到执行器后,不再须要保留可见性相干信息。

数据检索设计
对于AO表,每个事务会写不同的分片文件,所以AO表中元组的地位不再像Heap表中的线性构造,而是由分片文件编号(7位,范畴0~127)和文件外行号(40位)确定。AO表通过AOTupleId数据结构来示意AO表中元组的地址,因为元组地址会用到多个中央,比方索引、索引扫描等,所以AOTupleId采纳了和ItemPointerData同样的大小和对齐形式。AOTupleId一共48位6字节,以16位对齐。
AO表采纳的是变长块,和ItemPointerData不同的是,并不能简略的从AOTupleId对应到元组的物理地位。在Greenplum中,引入了块目录(BlockDirectory)的表和数据结构,来不便查找从分片文件号以及块外行号来取得在文件中的物理地位。只有当AO表上创立有索引时,块目录才会创立。
块目录表保护了从分片文件号、列组编号(columngroup_no,AO表始终为0,AOCS会用到)、起始行号三者到minipage的映射。minipage是由MinipageEntry组成的数组,每个MinipageEntry记录了一个或多个块的起始地位,蕴含如下信息:表MinipageEntry重要成员、firstRowNum 起始行号、fileOffset文件内偏移地位、rowCount 行数。
索引扫描或者位图扫描时,会通过AOTupleId读取单个元组,其扫描过程如下:
1、通过AOTupleId计算失去指标分片文件号segmentFileNum和行号rowNum。
2、如果以后关上分片文件不是segmentFileNum,则敞开以后文件,从新关上第 segmentFileNum号文件。
3、判断AOTupleId在块目录表中是否存在,如果不存在,阐明AOTupleId是旧的被回收的元组,或者之前异样终止事务插入的元组,这种状况下,返回读取失败。
4、通过VisibilityMap进行可见性查看,如果不可见,返回失败。
5、将文件的读取起止范畴设置为块目录表项中的起止范畴。因为块目录表项可能对应一个或者多个块,所以表项中记录的起始地位可能比理论的文件块大。
6、调用函数scanToFetchTuple在起止范畴内一一读取文件块,直到找到某个块满足:currentBlock.firstRowNum <= rowNum <= currentBlock.lastRowNum。如果没找到,则返回失败。
7、在块内查找查找行号为rowNum的元组并返回。
8、保留以后分片文件号,以后块起止行号,以后块目录信息,下次再次读取单个元组时,如果:
a、AOTupleId在以后起止行号之前,间接在以后块内查找元组,否则间接跳转到b。      b、在以后块目录范畴内,跳转到第4步开始执行。

数据可见性设计
AO表引入了另外一个辅助的Heap表pg_aoseg.pg_aovisimap_,称为VisibilityMap。该表记录了删除元组的信息,并且通过MVCC管制可奏效。如果删除胜利,通过该表就能查问到删除元组,从而判断元组不可见。如果每个删除的元组占用一行,显然不经济并且低效。大部分状况下,AO表中元组的拜访都是程序扫描,VisibilityMap借鉴了块目录表的思路,将多个相邻元组可见性信息放在一起存储。
Greenplumn中用位图来示意每个分片文件中元组的可见性,如果元组被删除,对应位图的比特地位1。每32768(APPENDONLY_VISIMAP_MAX_RANGE)个元组的可见性比特位作为一个位图存储在表pg_aoseg.pg_aovisimap_的visimap属性中。
Greenplum中在位图表上建设了索引,不便疾速查找。每个位图4096个字节,蕴含32768位,能够示意32768个元组的可见性。VisibilityMap通过函数AppendOnlyVisimapDelete_Init开始位图的批改,通过函数AppendOnlyVisimapDelete_Finish结束位图的批改。当某个行被删除时,须要判断该行对应的位图是否以及曾经在VisibilityMap表中已记录,如果是则读入内存中,否则初始化一个全零的位图。
AOCS列存的设计
AO表整个行一起存储,当须要读取属性内容时,首先须要读取变长块,解压缩,而后再获取其中一个属性的值。这样做有时代价十分高,即便查问只波及其中一个属性,也须要将所有内容读出来。在OLAP剖析畛域,列式存储是应答这种查问场景、进步性能的常见优化形式。Greenplum中也提供列式存储:AOCS
AOCS将不同的属性分成不同的文件存储。查问时,只须要读取须要的属性所对应的文件,其它属性不须要读入,节俭了磁盘IO开销。
同AO表一样,AOCS的拜访也不须要通过共享缓冲区管理器,间接从磁盘进行读写。另外,AOCS对数据的压缩做了非凡的解决,可能取得更好的体现。
AOCS表的存储相似AO表的存储,然而将每个列存储在独自的分片文件中,其中,第0到127号分片文件存储第一个属性,第128到255号分片文件存储第二个属性,顺次类推。其中,第0,128,256等文件逻辑上属于第0个分片文件,调配给Utility模式应用,第1,129,257等文件逻辑上属于第1个分片文件,顺次类推。
对于MPP模式,一个能够反对127个调配文件并发写。通过这种物理文件映射到逻辑分片文件的办法,AOCS表能够复用与AO表雷同的逻辑,比方AOTupleId、索引、VisibilityMap。
结语
HashData内核基于开源的PostgreSQL和Greenplum Database构建,元数据采纳开源的KV数据库FoundationDB提供长久化,通过ORC、Parquet等凋谢文件格式与其它大数据系统实现互通互联。
传统的Greenplum、Teradata等MPP 架构的数据库,存储、计算是紧耦合的,数据存储在本地零碎,存储能力的扩大通过减少集群节点实现,这样会导致计算资源重大节约,无奈满足业务的倒退。
作为一款企业级数据仓库产品,HashData在PostgreSQL和Greenplum Database等平台丰盛的剖析性能的根底上,针对云平台个性进行了大量改良和优化,实现了存算拆散、湖仓一体化,满足企业对海量数据的剖析与解决需要,减速企业数字化转型。

HashData研发、行业销售、工程服务等岗位正在炽热招聘中,欢送扫描下图二维码获取职位详细信息,和咱们随时分割!