技术探讨 | YMatrix 如何将 TPC-H 性能提升 10 倍?

本文深入探讨了 YMatrix 如何借助向量化执行引擎和列存系统,在 TPC-H 基准测试上达到 GPDB 性能的 10 倍。文章介绍了火山模型的优缺点,以及向量化执行引擎如何通过减少函数调用开销、改善缓存局部性和利用 SIMD 指令提升性能。此外,还讨论了 HashJoin 算法优化,包括 Join 顺序优化、Runtime Filter 和多种 HashMap 实现。通过算法选择、工程实践和向量化技术,YMatrix 成功实现了性能的巨大提升。
摘要由CSDN通过智能技术生成

在线处理分析场景对于 YMatrix 而言具有十分重要的意义,如何在该场景上使性能有数量级的提升呢?我们通过向量化执行引擎和列存系统,实现了性能在 TPC-H 基准测试上达到 GPDB 的十倍。本文将以 Hash Join 为切入点,介绍向量化执行引擎的基本原理,并深入分析、探讨 Hash Join 的算法和工程实践。


作者:数据库内核研发工程师 申磊

TPC-H(注1)是一套业内常用的决策支持基准测试,由 TPC 委员会制定发布,用于评测数据库的分析型查询能力。TPC-H 查询包含 8 张数据表、22 条复杂的 SQL 查询,大多数查询包含若干表 Join、子查询和 Group-by 聚合等。所选查询和数据库中的数据具有广泛的行业适用性。这个基准测试展示了决策支持系统的能力,可以检查大量数据、执行高度复杂查询、回答关键业务问题;同时反映了数据库系统处理查询的多方面能力。正因如此,我们选择 TPC-H 作为我们优化目标。

Greenplum (注2)(以下简称 GPDB)是全球领先的开源、并行大数据平台,专为分析、机器学习和 AI 而打造。GPDB 大数据平台基于 MPP(大规模并行处理)架构,具有强大的内核技术,包括数据水平分布、并行查询执行、专业优化器、线性扩展能力、多态存储、资源管理、高可用、高速数据加载等。从商业智能(BI)、文本、GIS、图、图像、流式数据处理到各种机器学习算法都能支持。此外,GPDB 提供的查询优化器是业界第一个开源的基于代价的查询优化器,专为大数据负载而设计。它可以将交互式和批处理模式分析扩展到 PB 级的大型数据集,而不会降低查询性能和吞吐量。

YMatrix 是基于 PostgreSQL / Greenplum 经典系开源数据库开发的超融合数据库产品。当前主要针对时序场景,而大部分时序数据库的查询场景可以认为是在线分析处理(OLAP)场景,因此我们选择业界领先的分析数据平台 GPDB 作为比较对象。

在打造向量化执行引擎开始时,我们就定了第一个小目标:性能是 GPDB 十倍。原因很简单,数据库作为基础软件,替换成本比较高,包括前期评估、测试成本、数据层面迁移成本、业务层面迁移成本、对新数据库完全掌控的成本、对业务迭代影响的成本,以及相关配套工具改造成本等等。整个过程需要 DBA、基础架构团队和业务团队协作,如果只是为了得到 50% 或一倍的性能提升,并不值得大动干戈。

本文以 TPC-H 查询为主线,讨论分析 YMatrix 如何在这套基准测试上达到GPDB性能的 10 倍。(测试报告全文

向量化执行引擎原理

首先,我们看一下 GPDB 的执行模型——火山模型——的优劣势。

1.1 火山模型

火山模型是数据库领域非常成熟的解释计算模型。该模型将关系代数中每一种操作抽象为一个 Operator,将整个查询构建成一个 Operator 树,从根节点到叶子节点自上而下地递归调用 next() 函数。

优势是实现简单,每个 Operator 单独实现即可。

缺点也很明显:

  • 函数调用开销:每条 Tuple 在各个节点之间流动时会涉及大量函数调用,虽然对于单条 Tuple 而言开销并不大,但考虑到数据规模,火山模型整体函数调用开销是显著的。如果涉及虚函数、函数指针,开销会更大一些;

  • 缓存不友好:火山模型每次处理一个 Tuple 的模式和过多的控制语句、函数调用等使得缓存失效的概率增加;

  • 无法充分利用现代 CPU 超标量能力。

几十年前,这个模型与当时的硬件能力相适应,能够匹配当时 CPU 和内存之间的速度比例。经过几十年发展,硬件有了长足的进步,值得注意的有:

  • 相比内存性能的提高,CPU 性能提高的更多;

  • 磁盘容量增长比 I/O 带宽增长更快,带宽是更稀缺的资源。

为了弥补火山模型的不足,并充分发挥现代硬件的能力,列存系统和向量化执行引擎应运而生。它们通过改变架构解决了上述两点导致的性能瓶颈转移问题,从最早的研究原型,转变为如今的数据库标配。

所以,如果想要使 YMatrix 性能在 TPC-H 基准测试上达到 GPDB 的十倍,打造列存系统和向量化执行引擎是必然选择。本文关注点是向量化执行引擎。

1.2 基于火山模型的向量化执行引擎

和常见的向量化执行引擎一样,我们的做法是基于火山模型的微批处理模式。从逻辑控制角度看,仍旧是火山模型;从数据角度看,一次处理一批数据(N 个 Tuple)而不是一个 Tuple。

数据按列存放,带类型信息,紧密排布,一个简单的 for 循环就能高效地处理一批数据,如下图所示。

这就弥补了火山模型的劣势,也是向量化的优势:

  • 减少函数调用开销:显而易见,函数调用开销被均摊了,只有原先的 1/N 。除了火山模型中最常见的 next() 之外,很多和业务相关的函数开销也被均摊了。比如写缓冲区,如果一次处理一个 Tuple,每次都必须检查缓冲区是否有足够的剩余空间;如果一次处理一批,成本就会被均摊,相当于 1/N 个 Tuple 检查一次缓冲区。

  • 更好的缓存局部性:数据跳转和指令跳转是流水线的大敌,更好的局部性意味着更好的性能。比如数据都在 L1 中,直接读取比从 L2 读取数据快 14 倍(数据来源参考:注3)。从数据缓存角度看,一个批次的大小设置成能放进缓存的大小是合适的。如果过大,超过 L1 缓存大小甚至超过全部共享缓存大小,数据需要从内存(或共享缓存)传输数据到 L1 缓存,使查询执行速度变慢。从指令缓存角度看,向量化函数的命令会迭代和批大小一样的次数,而不是像面向行的执行引擎那样执行 A 函数之后接着执行 B 函数等,指令局部性更好。

图以 select a + b from t where a % 2 = 0 为例演示了火山模型和向量化的执行流程。左上角方框表示数据在内存中的布局,一个是行存,一个是列存。算子左侧方框表示当前正在处理的数据。从图中可以看出,向量化数据和指令的局部性都更好,函数调用次数和 if-else 分支都更少。

此外,向量化的优势还有:

  • 充分利用编译器能力:如上所述,通过循环遍历数据紧密排布的原始类型数组及一些编程技巧,我们可以让编译器将我们的 C/C++ 代码自动编译为 SIMD 指令等更高效的形式。后续小节会详细介绍 SIMD 指令;

  • 自适应执行路径:我们根据运算的复杂程度选择不同的执行路径。对于像加法运算这样开销很低的算子,无论对应 Tuple 是否被过滤,向量化执行引擎都会对所有数据做处理。虽然会有些额外的运算,但是因为循环中没有 if-else 分支,所以能够生成SIMD 指令,执行速度比针对有效数据一个一个计算效率要高。下面讲解微批的优势,同时也是一个动态选择路径的例子;

  • 性能分析:由于均摊,收集性能数据的成本也比一次处理一个 Tuple 要小很多,这使得向量化引擎能够提供更详细的关于 CPU 开销的性能指标分析。如果面向行的执行引擎做同样细致分析,分析本身相对于处理的占比会增高,影响性能。通过更详细的性能分析做数据支持,更有助于做出正确的优化决策,从而提升性能,形成正向反馈;

  • 并行内存访问:在现代 CPU 上向量化循环执行内存访问的算法能够针对向量中不同值生成多个待处理的缓存未命中( outstanding cache misses )。这是因为当缓存未命中发生时,现代 CPU 能够提前推测,可以同时有多个待处理的缓存未命中。现代计算机对此支持的很好,基于此,内存带宽才能更好地被利用。工程实践的第一小节“搜索优化”是一个很好的例子。

一批处理多少数据呢?上限应该满足输入数据、输出数据外加辅助信息都能够放到 L1 缓存中这个条件,目的是避免频繁读写内存,充分利用缓存将这一批数据处理完;下限是至少能够利用 SIMD 指令做计算,同时能够达到有效均摊附加开销的目的。

不管为表示一批数据是否为 NULL,还是为表示这批数据是否被过滤条件选中,都使用一个 bitmap 字段表示,本质上是一个 uint64 数组,其中每个比特表示一个 Tuple 是否为 NULL 或者被过滤掉了。多个算子的结果基于 bitmap 位运算完成。当需要对这些数据做处理时,以很低代价判断出数据特征,选择不同方式执行计算,尽可能减少分支跳转,同时利用编译器优化能力达到更好的性能。

if (bitmap.Full() && bitmap.AllSet()) { // 满批,且全匹配
    // 编译器有机会进行循环展开、生成 SIMD 指令等优化处理
    // 同时,这里不需要再对 bitmap 进行检查
    for (auto i = 0; rowid < BATCH_SIZE; i++)
        // do something
} else if (bitmap.NoSet()) { // 不匹配
    // do n
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值