列式存储系列(二): Vertica

本文涉及的产品
EMR Serverless StarRocks,5000CU*H 48000GB*H
简介: 本文就 Vertica 的数据模型、存储、执行引擎以及这几个方面与 C-Store 的区别进行了简单的介绍。总的来说,Vertica 是一个纯正的列式存储数据库,为此,Vertica 设计实现了 projection 这一数据模型,并围绕该模型设计实现了一套大数据分析管理引擎。

作者:辛庸,阿里巴巴计算平台事业部 EMR 技术专家。Apache Hadoop,Apache Spark contributor。对 Hadoop、Spark、Hive、Druid 等大数据组件有深入研究。目前从事大数据云化相关工作,专注于计算引擎、存储结构、数据库事务等内容。

本文是列式存储系列的第二篇。在上一篇,我们介绍了C-Store,一个列式存储数据库。在本篇,我们讲述 C-Store 的继任者——Vertica。C-Store 是一个概念原型,在这个概念原型提出并发表后,Stonebraker 着手建立了一家公司研发商用的列式分析型数据库,公司名字就叫 Vertica。2011 年 Vertica 被惠普公司收购。2012 年,Vertica 公布了它的论文:《The Vertica Analytic Database: C-Store 7 Years Later》。Vertica 没有使用 C-Store 的任何代码,仅仅是借鉴了 C-Store 的某些设计思想。同时,对于 C-Store 一些设计不合理的地方,Vertica 提出了改进措施。在这篇文章里,Vertica 详细介绍了那些与 C-Store 不同的设计及其背后的设计考量。

Projection


C-Store 的核心概念是 Projections,即一张表的若干列子集构成一个 projection,多个 projection 的并集构成整张表。每个 projection 有自己的 sort-order。Projection 的概念类似于物化视图。但是物化视图要更为复杂,它往往还包含聚合、索引、join 等内容,而 projection 仅仅包含数据。Vertica 继承了 C-Store 的这个概念。

1
上图是 projection 的一个示例。对于一张原始表,它被拆分成了两个 projection。第一个 project 包含原表的全部五个字段,并按照 date 排序。第二个 projection 包含两个字段,并按照 cust 排序。在 Vertica 中,数据被分段(segment)存储到不同的节点。每个 projection 有不同的分段依据。在第一个 projection 中,分段依据为 hash(sale_id),第二个 projection 中,分段依据为 hash(cust),即图中浅色的字段。

在 C-Store 的介绍文章中我们有提到,projection 的设计的核心难点在于,如何根据几个 partial projection 还原出原表,因为不同的 projection 中数据的排序都是不一样的。C-Store 采用了一种 Join-Index 的做法(具体原理请参考上一篇文章)。Vertica 没有采用 Join-Index,而是要求所有的表都必须要有一个 super projection,即包含所有列的 projection。之所以不采用 Join-Index 是因为维护 Join-Index 的负担过重,已经远远超出了 projection 设计带来的好处。不过这里笔者有点疑惑,根据 Join-Index,我们能够根据 partial projections 还原出原 row(或者原 row 的一部分),但是 Vertica 没有 Join-Index,要根据 partial projection 获得原 row(或者原 row 的一部分)是不可能的,我们只能从 super projection 去读。例如,假设原表有 200 个列,super projection 包含全部的列。projection 1 包含列 3,4,5,并且按照列 3 排序,projection 2 包含列 5,6,7,并且按照列 5 排序。如果要查询列 3,4,5,6,7,我们不能从 projection 1 join projection 2 得到结果,只能读 super projection。这样看来,Vertica 实际上牺牲了 C-Store projection 的灵活性。可惜的是 Vertica 论文并没有交代这些细节。

除此之外,Vertica 还保留了 C-Store 中设计的 prejoin projection,即一个 projection 可以包含多张表(如一张事实表和多个维表)的列,只要它们之间存在外键关系即可。

Partitioning 和 Segmentation


同其他数据库类似,Vertica 支持分区(Partitioning)。Vertica 的分区在物理上的表现是在一个节点内部,对存储划分不同的 logical region,这样就能达到并行处理不同分区的能力。除了分区,Vertica 还支持分段(Segmentation)。在上一小节有提到,对于一个 projection,会按照其中一个字段 hash 为一个个独立的 segments,然后将 segments 分发到不同的 nodes 存储。与分区不同的是,分段是在节点间扩展的,而分区是在节点内。

Vertica 的 projection 可以有副本(replica)。副本也按照 segment 存储。副本设计的优点是一方面增加了系统的可用性,另一方面也能够在一定程度上提高并发性。
image
对于分区和分段,我们也能够从其他的分布式系统中看到一些类似的设计。对于 Hive 这种 Hadoop based 的 NoSQL 系统,由于存储本身为分布式存储,因此上层大体上是不太管怎么存的,但是上层必须要根据 HDFS 上 block 的存储做本地性优化。这个有点类似于 Vertica 的分段,均是大文件跨节点存储。在开源搜索系统 Elasticsearch 中,一个索引被划分为 Shard,并跨节点存储,也是和这里的分段类似的。ES 的 Shard 也有 replica。可见,在分布式环境下对存储做分区和分段,是一种通常的做法。

ROS 和 WOS


Vertica 实现了 ROS(Read Optimized Store)和 WOS(Write Optimized Store),其作用和 C-Store 中的 RS 和 WS 类似。ROS 负责管理存储在磁盘上的数据,而 WOS 则运行在内存中,用于应对频繁的 Insert/Delete/Update 等操作。当 WOS 中的数据到达一定量之后,会运行 Tuple Mover 将 WOS 中的数据移动至 ROS。

C-Store 的 RS 主要负责存储 segments 数据和相应的 Join-Index,而在 Vertica 中没有 Join-Index,因此这部分数据就不用存了。但是 ROS 还存了另外一类数据:Position-Index。Position-Index 不是存储每一条数据的 position,而是有点类似于 Parquet 文件中的 meta。它记录了磁盘上每个数据块的起始位置、数据的最大值最小值等信息。这些信息可以用来在运行时过滤数据。

ROS 有个概念叫做 ROS container。一个 container 是一个小的“容器”,容纳一部分数据。这样做的好处是可以在一定程度上提高数据处理的并发性(节点内并发)。图 3 展示了一个 projection 在一个 node 内的存储状况。

image

在这个例子中,首先数据在节点内是分区的,分区列为 MONTH/YEAR,分为 3/2012、4/2012、5/2012、6/2012 四个区。然后数据根据 hash(cid) 分段,分为三个段:Segment 1,2,3. 每个段的数据占用一定数量的 container 用于存储数据,在这里有 14 个 container。对于每个 column,Vertica 存储两个文件:数据文件和 Position-Index,这样总共有 28 个数据文件和 28 个 Position-Index 文件。

Execution Engine


Vertica 设计了一套并行化的、管道式的执行引擎。这一部分的介绍比较枯燥乏味,并且和其他的 pipline 式的 SQL 执行引擎大同小异(如 impala、presto 等)。这里介绍一下 Vertica 论文中特意提到的执行引擎的优化点。

1.Sideways Information Passing(SIP)。名字非常高大上,但是原理比较简单,就是利用一些“不是非常直观的信息”生成 predicate。所谓“不是非常直观的信息”就是从 plan 中 infer 出来的信息。比如对于 HashJoin,如果表被 hash 的表较小,那么可以提前 collect 相应的值,分发到大表端进行过滤数据。这个特性 Hive 也有,叫做 “Runtime Filter”。另外,EMR-Spark 也实现了这个特性,有兴趣的同学可以测试体验一下。Vertica 的 SIP 除了 Hash Join 还用到了 Merge Join 上,但是论文没有具体讲。

2.算法的运行时调整。比如 HashJoin 发现 Hash table 在内存中无法放下,它会转为 Merge Join。

3.Prepass 算子。它本质上是多线程的预先执行一些操作,然后这些操作的结果可以被下游的 operator 利用生成最终结果。Vertica 给了个例子,如图 4 所示。对于 GroupBy,Vertica optimizer 会生成几个 stage 来执行。其中第一个 stage 会生成一个 L1 缓存同等大小的 HashTable(从这点上看,Vertica 确实做到了硬件级别的优化),用来预先聚合数据(图 4 中倒数第二个算子),并把这些数据发送到下游。当一批数据聚合好后 clear 掉 HashTable,再聚合下一批。最终的 GroupBy 是在正数第三个算子实现的。从这个原理上看,我觉着与其叫做 Prepass,不如叫算子下推更为合适一些。
image

1.JIT(Just-in-time Compilation)。在很多计算中,计算都是类型相关的。为了避免类型判断带来的开销以及虚调用,很多计算引擎利用了 JIT 技术来提升性能,Vertica 也不例外(这几乎成了现在 SQL 执行引擎的标配了)。不过 JIT 是一个非常考验技术的技术,JIT 做的好并不容易。

其他


讲了数据模型、存储和计算引擎,Vertica 的核心就介绍完了。Vertica 的论文还介绍了 Tuple Mover、事务管理、容灾等细节,这里就不介绍了,有兴趣的读者可以参阅论文。

总结


本文就 Vertica 的数据模型、存储、执行引擎以及这几个方面与 C-Store 的区别进行了简单的介绍。总的来说,Vertica 是一个纯正的列式存储数据库,为此,Vertica 设计实现了 projection 这一数据模型,并围绕该模型设计实现了一套大数据分析管理引擎。在 NoSQL 风起云涌的时代,Vertica 能够凭借自身良好的设计,在广大 NoSQL 方案包围圈里争得一席之地,且没有开源优势,充分说明了它的实力。

参考文献
[1] Andrew Lamb et.al. The Vertica Analytic Database: C-Store 7 Years Later. In VLDB, pages 1790-1801, 2012.

_

相关实践学习
基于EMR Serverless StarRocks一键玩转世界杯
基于StarRocks构建极速统一OLAP平台
快速掌握阿里云 E-MapReduce
E-MapReduce 是构建于阿里云 ECS 弹性虚拟机之上,利用开源大数据生态系统,包括 Hadoop、Spark、HBase,为用户提供集群、作业、数据等管理的一站式大数据处理分析服务。 本课程主要介绍阿里云 E-MapReduce 的使用方法。
相关文章
|
存储 NoSQL 关系型数据库
|
存储 消息中间件 NoSQL
聊一聊数据库的行存与列存
好多人最开始学习数据库的时候,是关系数据库,数据以表格形式存储,一行表示一条记录。其实这种就是典型的行存储(Row-based store),将表按行存储到磁盘分区上。 而一些数据库还支持列存储(Column-based store),它将表按列存储到磁盘分区上。
聊一聊数据库的行存与列存
|
存储 算法 数据挖掘
行式存储和列式存储的区别
行式存储和列式存储的区别
1011 0
|
存储 NoSQL OLAP
Kudu入门_对比_列式和行式|学习笔记
快速学习Kudu入门_对比_列式和行式
Kudu入门_对比_列式和行式|学习笔记
|
7月前
|
关系型数据库 OLAP 分布式数据库
PolarDB 开源版通过 duckdb_fdw 支持 parquet 列存数据文件以及高效OLAP
背景PolarDB 的云原生存算分离架构, 具备低廉的数据存储、高效扩展弹性、高速多机并行计算能力、高速数据搜索和处理; PolarDB与计算算法结合, 将实现双剑合璧, 推动业务数据的价值产出, 将数据变成生产力.本文将介绍PolarDB 开源版通过duckdb_fdw 支持 parquet 列存...
603 0
|
存储 并行计算 算法
PolarDB 开源版通过 duckdb_fdw 支持 parquet 列存数据文件以及高效OLAP
PolarDB 的云原生存算分离架构, 具备低廉的数据存储、高效扩展弹性、高速多机并行计算能力、高速数据搜索和处理; PolarDB与计算算法结合, 将实现双剑合璧, 推动业务数据的价值产出, 将数据变成生产力. 本文将介绍PolarDB 开源版通过duckdb_fdw 支持 parquet 列存数据文件以及高效OLAP.
1712 0
|
存储 算法 NoSQL
【数据库系列】什么是列式存储和行式存储
列式存储:每一列单独存放,数据即是索引。只访问涉及得列,如果我们想访问单独一列(比如NAME)会相当迅捷。一行数据包含一个列或者多个列,每个列一单独一个cell来存储数据。行式存储: 把一行数据作为一个整体来存储。学习:https://blog.csdn.net/qq_43543789/article/details/108662140。......
803 0
【数据库系列】什么是列式存储和行式存储
|
前端开发 数据库 数据库管理
【DBMS 数据库管理系统】数据仓库 数据组织 ( 数据组织级别 | 元数据 | 粒度 | 分割 | 数据组织形式 )(一)
【DBMS 数据库管理系统】数据仓库 数据组织 ( 数据组织级别 | 元数据 | 粒度 | 分割 | 数据组织形式 )(一)
362 0
|
存储 监控 分布式数据库
解密OpenTSDB的表存储优化
本篇文章会详细讲解OpenTSDB的表结构设计,在理解它的表结构设计的同时,分析其采取该设计的深层次原因以及优缺点。它的表结构设计完全贴合HBase的存储模型,而表格存储(TableStore、原OTS)与HBase有类似的存储模型,理解透OpenTSDB的表结构设计后,我们也能够对这类数据库的存储
28192 0
|
SQL 存储 数据库
MonetDB 列存数据库架构初探
### 前言 对于越来越多的分析型场景,例如数据仓库,科学计算等, 经典的数据库DBMS的检索性能颇显乏力。 相反的,最近出现了很多面向列存的数据库DBMS,像ClickHouse,Vertica, MonetDB等,因其充分利用了现代计算机的一些硬件优势,同时舍弃了一些DBMS特性,得到了非常好的检索性能。本文就MonetDB, 整理一些资料和代码,简单介绍其核心设计。 通过简单Benc
5712 0