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