写点什么

详解数仓的向量化执行引擎

  • 2024-04-25
    福建
  • 本文字数:2251 字

    阅读完需:约 7 分钟

前言


  • 适用版本:【基线功能】


传统的行执行引擎大多采用一次一元组的执行模式,这样在执行过程中 CPU 大部分时间并没有用来处理数据,更多的是在遍历执行树,就会导致 CPU 的有效利用率较低。而在面对 OLAP 场景巨量的函数调用次数,需要巨大的开销。为了解决这一问题,GaussDB(DWS)中增加了向量化引擎。向量化引擎使用了一次一批元组的执行模式,能够大大减少遍历执行节点的开销。同时向量化引擎还天然对接列存储,能够较为方便地在底层扫描节点装填向量化的列数据。列存 + 向量化执行引擎,是打开 OLAP 性能之门的金钥匙之一!


关于行存、列存表


行存表按行存储 tuple 到 Page 页面。多用于 TP 场景,这些场景数据频繁更新,增删改操作多,查询结果涉及表的多列。



列存表按列存储,每列数据存储到一个文件。多用于 AP 场景。

  • 表列数多,访问列数少,减少 IO 操作次数

  • 列数据具有同质性,提高数据压缩比

  • 基于列批量数据的运算,CPU 的 cache 命中率高



执行框架


执行器是优化器与存储引擎的交互枢纽。以优化器生成的执行计划树为输入,从存储引擎访问数据,并按照计划,操作各种执行算子,从而实现数据的处理。采用 Pipeline 模式, 行执行器一次一 tuple,列执行器一次一 batch。上层驱动下层,使得数据在执行树上流动。提供各种数据处理的执行算子。下图展示了自上而下的控制流和自下而上的数据流。



执行器的执行过程可分为这三个步骤:

  1. 执行器初始化:构造执行器全局状态信息 estate、递归遍历计划树各节点,初始化其执行状态信息 planstate

  2. 执行器的执行:行引擎和向量化引擎入口独立开,从计划树根节点开始,递归遍历到叶节点获取一个 tuple/batch,经过逐层节点算子的处理,返回一个结果 tuple/batch,直到再无 tuple/batch。

  3. 执行器的清理:回收执行器全局状态信息,清理各 plan node 的执行状态。



列执行器


行执行器的问题是:CPU 大部分处理在遍历 Plan Tree 过程,而不是真正处理数据,CPU 有效利用率低。列存表独有的应用场景,需要配套的向量化引擎,才能真正发挥其在 OLAP 场景下提升性能的优势。因此,列执行器的改造基本思路为:一次处理一列数据。


和行执行器一样,向量化执行引擎调度器,遵循 Pipeline 模式,但每次处理及在算子间传递数据为一次一个 Batch(即 1000 行数据),CPU 命中率提高,IO 读操作减少。列执行器的数据流结构 VectorBatch 如下图所示。



行列混合:Adapter 算子


列存表的某些场景不支持向量化执行引擎,譬如:string_to_array、listagg、string_agg 等。GaussDB 具有将两套行列引擎自动切换的能力。



针对列存数据,如果只有行引擎,通常需要将列数据重构成元组 tuple 给执行引擎逐行处理。Tuple deform 过程影响列存数据查询处理的性能。


向量化执行引擎的性能


对比行列存引擎对同一表达式 x*(1-y)计算的性能,可以看到列存引擎的 Cstore Scan 算子相比行存引擎的 Seq Scan 算子,耗时减少了 85%。



向量计算的特点是:一次计算多个值,减少函数调用和上下文切换,尽量利用 CPU 的缓存以及向量化执行指令提高性能。


向量化执行引擎的性能优势:

  • 一次一 Batch,读取更多数据,减少 IO 读次数

  • 由于 Batch 中记录数多,相应的 CPU 的 cache 命中率提升

  • Pipeline 模式执行过程中的函数调用次数减少

  • 与列存表配套,减少 tuple deform,即列存数据重构 tuple 的时间开销


行/列执行器各算子对照


向量化引擎的执行算子类似于行执行引擎,包含控制算子、扫描算子、物化算子和连接算子。同样会使用节点表示,继承于行执行节点,执行流程采用递归方式。主要包含的节点有:CStoreScan(顺序扫描),CStoreIndexScan(索引扫描),CStoreIndexHeapScan(利用 Bitmap 获取元组),VecMaterial(物化),VecSort(排序),VecHashJoin(向量化哈希连接)等,下面将逐一介绍这些执行算子。


扫描算子


 扫描算子用来扫描表中的数据,每次获取一条元组作为上层节点的输入, 存在于查询计划树的叶子节点,它不仅可以扫描表,还可以扫描函数的结果集、链表结构、子查询结果集。一些比较常见的扫描算子如表所示。



连接算子


连接算子对应了关系代数中的连接操作,以表 t1 join t2 为例,主要的集中连接类型如下:inner join、left join、right join、full join、semi join、 anti join,其实现方式包括 Nestloop、HashJoin、MergeJoin;



物化算子


物化算子是一类可缓存元组的节点。在执行过程中,很多扩展的物理操作符需要首先获取所有的元组才能进行操作(例如聚集函数操作、没有索引辅助的排序等),这是要用物化算子将元组缓存起来;



控制算子


控制算子是一类用于处理特殊情况的节点,用于实现特殊的执行流程。



其他算子


其他算子包括 Stream 算子,以及 RemoteQuery 等算子



Gaussdb 向量化的演进


在第一代向量化引擎之后,GaussDB 演化出具有更高性能的向量化引擎:Sonic 向量化引擎和 Turbo 向量化引擎。GaussDB 为了 OLAP 执行性能提升,在列存 + 向量化执行引擎、批量计算的路上不断演进:


  • Stream 算子 + 分布式执行框架,支持数据在多节点间流动

  • SMP,节点内多线程并行,充分利用空闲硬件资源

  • LLVM 技术,全新的代码生成框架,JIT(just in time)编译器,消除 tuple deform 瓶颈

  • Sonic 向量化引擎,对 HashAgg、HashJoin 算子进一步向量化,根据每列不同类型实现不同 Array 来对数据做计算

  • 新一代 Turbo 向量化引擎,对大部分算子做进一步向量化,在 Sonic 引擎的基础上,新增了 Null 优化、大整数优化、Stream 优化、Sort 优化等,进一步提升了性能


总结


本文介绍了 GaussDB 向量化执行引擎,对其框架、原理、各算子概况、性能提升等做了详细阐述。


文章转载自:华为云开发者联盟

原文链接:https://www.cnblogs.com/huaweiyun/p/18156802

体验地址:http://www.jnpfsoft.com/?from=infoq

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
详解数仓的向量化执行引擎_Python_快乐非自愿限量之名_InfoQ写作社区