YashanDB向量化执行引擎如何给海量数据分析提速

作者介绍:李伟超,数据库系统架构师,YashanDB架设技术开发负责人,10年以上数据库内核技术开发经验。

*全文4510个字,阅读时长约11分钟。


背景

海量数据OLAP场景,通常具有数据规模大、查询复杂度高、处理速度要求高等特点,对SQL引擎的执行效率要求非常高。面向行式存储的行式执行引擎由于逐行扫描的方式,往往会导致大量的函数调用开销,性能方面无法满足业务需求。为了解决这个问题,基于列式存储的向量化执行引擎技术应运而生,该方式通过批量计算和充分利用CPU高速缓存和流水线,使得查询分析的性能相较于行式执行引擎得到数量级的提升。面向OLAP场景,YashanDB在列式存储基础上引入了向量化执行引擎技术,并取得了显著的查询性能提升。如下图,在TPC-H基准测试下,YashanDB基本维持秒级的查询响应时延,达到了行业领先水平。本文将为大家深入介绍向量化执行引擎的场景价值、技术优势以及YashanDB的实现机制。

a45ea7ebb89d4c6733f693cd617cdf2f.jpeg

图1 TPC-H测试结果

硬件配置:2288虚拟机(16核,160G内存,3.4T SSD)

软件版本:OS(CentOS 7),DB(YashanDB 22.2)

测试模型:TPC-H 100G数据


为什么需要向量化计算?


讲到向量化执行引擎,首先想到的问题是为什么需要向量化计算以及它是如何提升计算性能的?要回答这个问题,我们先回顾一下传统的行式执行引擎是如何做的。传统的行式执行引擎普遍采用的是经典的火山模型,例如MySQL、PostgreSQL等数据库都采用的是该执行模型。

火山模型的执行方式是从底层数据源向上拉取数据,这种方式也被称为“Pull模型”。

如下图所示,对于一个查询计划,上层算子每调用一次下层算子的next函数,下层算子向上返回一条记录,持续这个过程直至下层算子不再返回记录。它的逻辑简洁,易于理解和实现,一次一条记录的执行方式比较适合对查询响应时间有较高要求的OLTP场景,但是在面向海量数据分析时存在着严重的不足:每次一条记录的执行模式导致上下层算子之间以及表达式计算存在大量的函数调用开销,并且不能充分利用CPU高速缓存和流水线。 8537f4a2b6d133ed0a0b669f3461c944.jpeg

图2 火山模型执行方式


针对上面问题的改进方案,业界目前主要有两种方式:一种是基于JIT即时编译(Just-in-time Compilation)的查询优化,利用LLVM等编译框架对查询计划做运行时优化,通过内联优化等手段消除函数调用开销;另一种方式就是本文要讲的基于列存的向量化计算。要实现基于JIT的查询优化,需要对编译原理和LLVM等编译框架有深入的理解,对开发人员的技术要求以及工程实现的复杂度都较高,并且对编译框架有深度的耦合。相较而言向量化执行模型在OLAP场景批处理方面更有优势:基于局部性原理,对批量数据的计算能够更好的利用CPU缓存和流水线;同时,针对批量数据还可以利用SIMD指令实现向量化计算。

a8cbdc9d6eb250ebe116f36633c7e831.jpeg

图3 向量化模型执行方式


如何实现向量化执行引擎?


实现向量化执行引擎主要包括以下几个方面的工作:
  • 基于列存的组织结构:为了实现对数据的向量化计算,需要设计按列组织的内存结构,以充分利用CPU的缓存以及使用SIMD指令加速计算。

  • 向量化的计算框架:在列存内存组织的基础上,提供一套基于列存的算子和表达式框架,以支持灵活可扩展的定义和实现各类算子和表达式。

  • 针对查询计划执行的优化技术:通过优化器、向量化执行引擎和存储引擎的紧密配合,实现将查询条件下推到存储引擎以及针对HashJoin实现运行时过滤(Runtime Filter)。

  • 内存管理:包括运行时的动态内存管理和针对物化算子的物化内存管理。


01 基于列存的组织结构


在向量化执行引擎模型中,列式存储占据着天然的优势。因为列存中数据以数组的形式存储,一列中的所有数据都会被同时读取和处理,这种方式与向量化计算非常吻合。向量化执行引擎以每次一批记录的方式执行,每批记录都是以列存的方式组织的。在向量化执行引擎中,列存数据的组织结构非常重要,因为它直接影响着计算效率。我们首先来看一下在向量化执行引擎中列存数据的组织结构。


7cb0315d56da38d9061dcc1dd1b219e0.jpeg

图4:YashanDB基于列存的组织结构


  • ColumnSet:我们将以列存的方式组织到一起的一批记录称为ColumnSet,它是一个二维的数据集,由许多相邻的向量组成,每个向量的记录数相同,不同向量之间按行逻辑对齐。与表类似,ColumnSet也有一个Schema,该模式必须匹配其向量的数据类型。ColumnSet是一个便于序列化和计算的工作单元,每个ColumnSet还有一个可选的位图用来表示ColumnSet中的行是否有效。

  • Schema:用来描述二维数据集的结构。它包含一系列Field和一些可选的模式范围的元数据。Field描述列的名称及其元数据。

  • Column:是一个与Field绑定在一起的分块向量,同时列还有一个可选的位图用来表示列中的值是否为空值。根据数据类型分为定长列(Fixed Length Column)和变长列(Variable Length Column)。定长列可以对数据直接按下标随机访问;而变长列需要先根据偏移向量计算出数据的起始位置和长度,然后访问数据。

  • Vector:表示已知长度并具有相同数据类型的标量值的序列。向量中的值由一块连续的内存存储,值的数量和意义由向量的数据类型决定。


02 计算框架


YashanDB基于Rust语言自主研发了高性能的向量化执行引擎,具备以下特点:
  • 内存安全,高性能;

  • 基于ColumnSet的批量计算,实现只读数据、无锁并发的向量化计算;

  • 支持功能丰富的表达式计算和算子,完整支持TPC-H、TPC-DS语法;

  • 高度灵活的可扩展性。

如下所示, 在向量化计算框架中有两个基本概念及其接口:算子(Operator)和表达式(Expression)。任何算子和表达式只要实现了对应的接口,就可以对接到向量化执行引擎中。它们在运行时通过绑定资源生成可执行的游标(Cursor)和绑定表达式(BoundExpression),消费下层节点的数据,并向上层节点返回生成的数据,消费和生成数据都是每次一批记录。

pub trait Operator {
fn bind(&self, ctx: Arc<dyn Context>) -> Result<Box<dyn Cursor>>;
}

pub trait Cursor {
fn next(&mut self) -> Result<Option<ColumnSet>>;
}

pub trait Expression {
fn bind(&self, ctx: Arc<dyn Context>, schema: &Schema) -> Result<Box<dyn BoundExpression>>;
}

pub trait BoundExpression {
fn evaluate(&mut self, column_set: &ColumnSet) -> Result<Arc<dyn Column>>;
}


03&nbsp;条件下推


条件下推是指过滤条件从执行引擎下推到存储引擎, 列存存储利用稀疏索引进行快速过滤,大部分场景可显著减少数据的读取,提高查询性能。存储支持模糊过滤(仅仅用稀疏索引过滤)和精确过滤,如果存储执行的是模糊过滤,执行引擎还会进行过滤。

条件下推的规格:

  • 支持多个字段的AND条件下推;

  • 单个字段的多个条件,条件是OR的关系;

  • 条件为等值查询和范围查询,比较值必须是常量。

列存存储对条件下推的支持:
  • Extent粒度的布隆过滤:支持等值条件;

  • 块粒度的稀疏索引过滤:支持and,or,<,>,=,>=,<=,in等运算下的常量表达式;

  • 支持编码数据的行级过滤;

  • 向量化过滤计算。


3379e0ee1bd70f2afeb982a0d3c7e012.jpeg

图5:YashanDB 条件下推示意


04&nbsp;运行时过滤


条件下推是将用户输入的查询条件下推,但还有一种类型就是HashJoin这类场景,会使用运行时过滤(Runtime Filter)来加速。 根据字面意思,这是一种"运行时过滤条件",和普通的Filter的区别在于它不是在SQL语句中定义的,而是在运行时根据中间数据生成的。
e1d7f2a5b6e7f862ec09cace72fad1ec.jpeg 图6&nbsp; No RuntimeFileter 和&nbsp;RuntimeFileter示意

目前YashanDB实现的Runtime Filter支持的过滤方式是Bloom Filter(布隆过滤器)。HashJoin通常右表为小表,左表为大表,分别称为Build表和Probe表,其执行过程大致为:

  • 取出Build表所有数据;

  • 根据Build表数据构建HashTable;

  • 再取出Probe表所有数据,同时基于HashTable生成Join结果;

HashJoin中的Runtime Filter是在构建HashTable时同时创建的:利用计算得到的hash值生成Bloom Filter。然后在取出Probe表数据之前,将生成的Runtime Filter在Probe表侧进行下推,通常是下推到最底层的TableScan上。这样TableScan扫描出来数据之后,可以利用下推的Runtime Filter先过滤一部分数据,减少返回的数据量,更少的数据量带来的是更小的计算量,性能自然就会提升。但是Runtime Filter并不总是有效的,如果Runtime Filter的过滤效果不好,TableScan不能有效减少返回的数据量,同时由于应用Runtime Fiter引入了额外的计算Hash值的开销,性能反而可能会下降。

针对这种情况,YashanDB在应用Runtime Filter时会检测其过滤效果,过滤效果较差时会禁用掉下推的Runtime Filter,避免性能劣化。以TPC-H模型的Q17为例,开启Runtime Filter之后耗时从7s左右变成1s左右。


05&nbsp;动态内存管理&nbsp;


OLAP场景的计算过程中需要处理大批量的记录,系统通常需要进行频繁的内存申请和释放以应对这种需求。然而,这种频繁的内存操作会导致内存碎片化,进而增加了内存管理开销。

在列存组织结构中我们介绍到,计算过程中每次处理一批记录,即一个ColumnSet。每批记录的行数我们称为BulkSize,在一次计算过程中BulkSize是不变的,那么对于定长的数据类型列,比如int类型列,其每批记录占用的内存大小是固定的,都为size_of(int) * BulkSize。这块内存理论上来讲是可以被不同批次的ColumnSet中的相同列重复使用。

为解决这些问题,我们采取了一些优化策略。根据向量化执行引擎的运行时特点,YashanDB实现了一个定制化的动态内存管理机制——基于MemPool和Allocator的两级内存缓存机制,通过一套全局的缓存内存池和细粒度的内存分配器实现了高效的内存管理。
31fd9025feb9331030ca78ba49943c04.jpeg图7&nbsp; YashanDB动态内存管理机制

MemPool是一个全局共享的内存池,通过MMAP/MUNMAP向操作系统申请和释放内存,支持设定内存配额,在达到内存配额上限时,可以按策略淘汰空闲内存。

Stage(YashanDB中可执行的最小单元)粒度的Allocator:每个Stage会分配一个Allocator,Satge执行过程中的内存申请和释放优先在Allocator中进行,可以有效减少并发的内存申请释放的锁冲突。Allocator的内存从MemPool分配,Stage执行结束时,Allocator的内存会全部归还给MemPool。Allocator同样支持自定义的空闲内存淘汰机制。

MemPool和Allocator的内存缓存都是基于Arena实现的。Arena就是一个空闲内存块(Block)的缓存池,以链表进行管理。根据常用的内存大小定义了多个SizeClass,并且根据内存大小进行不同的管理:

  • 大内存:不同的SizeClass使用大小不同的Block,进行Block级别管理;

  • 小内存:不同的SizeClass使用大小相同的Block,Block切分成大小不同的Region,进行Region级别的管理;由于不同SizeClass使用的Block大小是相同的,在某个SizeClass无空闲内存时,可以先从具有相同Block大小的SizeClass中窃取空闲内存块,都没有时,再向内存池申请;

  • HUGE内存:大于2M的内存块,不进行缓存处理,执行通过MMAP/MUNMAP向操作系统申请和释放。


06&nbsp;物化内存管理


向量化执行引擎在执行查询计划过程中,当遇到需要物化的算子时,会在内存中缓存数据。然而,当内存不足时,需要把内存数据写到外部存储。在执行计划中,可能有多个需要物化的算子,这些算子所使用的内存总量受到限于可用内存资源的影响。

传统的方法是按照计划给出来的评估值给出一个配额,超过这个值就写盘。这种方式的主要问题是执行所需要的内存是动态的,单一的配额导致不能有效利用内存。

YashanDB采用动态分配配额的方式来管理物化内存,将物化内存分成全局、SQL、Stage、算子四个级别。一条SQL语句执行前,根据计划评估结果,为物化内存分配合理的内存配额,并为其对应的Stage、算子也会分配合理的配额。执行过程中,可以在配额范围内动态申请内存,配额不足时可以自下而上申请更多的配额。当配额用完后,会将数据写到外部存储。
b84b02fc525ec033e48d1d9d2d5102d0.jpeg图8&nbsp; YashanDB物化内存管理


总结


向量化执行引擎的设计需要充分考虑多个方面的因素,包括存储数据结构、计算框架、优化技术以及内存管理等,这直接决定数据库的性能和效率。 为了更好地满足各种复杂业务场景的需求,YashanDB的向量化执行引擎已经完整支持了国际基准测试TPC-H和TPC-DS的语法,并且在TPC-H数据分析型基准测试中取得了优异的性能表现。

向量化执行引擎是一个复杂的系统工程,随着硬件的不断演进,向量化执行引擎的技术演进将会是一个持续发展和优化的过程。在下一个版本中,我们会进一步提升TPC-DS的查询性能以及在行存列存混合计算场景方面的支持。

随着不断的优化改进,我们相信YashanDB的功能和性能会持续增强,进而更好的满足各种复杂业务场景的需求。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/142599.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

9月27日星期三今日早报简报微语报早读

9月27日&#xff0c;星期三&#xff0c;早报简报微语早读分享。 1、兰州&#xff1a;拟明年起奖励医保参保人连续缴费&#xff0c;提高其住院报销比例&#xff1b; 2、中国民办教育协会&#xff1a;10月15日起全面禁止校外培训系误读误解&#xff1b; 3、山西修订未成年人保…

外包干了3个月,技术退步明显。。。。。

先说一下自己的情况&#xff0c;大专生&#xff0c;17年通过校招进入广州某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

根据命令行参数动态导入模块或文件

需求 在命令行运行一个 python 文件&#xff0c;同时传入自定义参数&#xff1a; $ python main.py --nodeTable --actioncreate --data"{name: test2, is_sys_obj: False, encoding: UTF8,datconnlimit: -1, variables: []"希望 main.py 接收命令行参数&#xff0…

Flutter笔记:滚动之-无限滚动与动态加载的实现

Flutter笔记 无限滚动与动态加载的实现 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/133342307 目 录…

Goby 漏洞发布|泛微 E-office flow_xml.php 文件 SORT_ID 参数 SQL 注入漏洞

漏洞名称&#xff1a;泛微 E-office flow_xml.php 文件 SORT_ID 参数 SQL 注入漏洞 English Name&#xff1a; Weaver E-office flow_xml.php file SORT_ID parameter SQL injection vulnerability CVSS core:7.8 影响资产数&#xff1a; 21632 漏洞描述&#xff1a; 泛微…

前端知识总结

在前端开发中&#xff0c;y x是一种常见的自增运算符的使用方式。它表示将变量x的值自增1&#xff0c;并将自增后的值赋给变量y。 具体来说&#xff0c;x是一种后缀自增运算符&#xff0c;表示将变量x的值自增1。而y x则是将自增前的值赋给变量y。这意味着在执行y x之后&am…

linux使用操作[2]

文章目录 版权声明网络传输ping命令wget命令curl命令端口linux端口端口命令和工具 进程管理查看进程关闭进程 主机状态top命令内容详解磁盘信息监控 版权声明 本博客的内容基于我个人学习黑马程序员课程的学习笔记整理而成。我特此声明&#xff0c;所有版权属于黑马程序员或相…

设计模式-迭代器模式

介绍 顺序访问一个集合使用者无需知道集合的内部结构&#xff08;封装&#xff09; 示例 常用的jQuery演示 <p>jquery each</p> <p>jquery each</p> <p>jquery each</p><script> var arr [1,2,3] var nodeList document.getEl…

【Unity】LODGroup 计算公式

Unity 在配置 LodGroup 时&#xff0c;其分级切换的计算方法是按照物体在相机视野中占据的比例计算的。在运行时&#xff0c;如果相机视野范围&#xff08;Field of View&#xff09;没有改变&#xff0c;那么这个值可以直接换算成物体距离相机的距离。这里就讨论下如何计算得到…

Jmeter——循环控制器中实现Counter计数器的次数重置

近期在使用Jmeter编写个辅助测试的脚本&#xff0c;用到了多个Loop Controller和Counter。 当时想的思路就是三个可变的数量值&#xff0c;使用循环实现&#xff1b;但第三个可变值的数量次数&#xff0c;是基于第二次循环中得到的结果才能确认最终次数&#xff0c;每次的结果…

华南理工大学电子与信息学院23年预推免复试面试经验贴

运气较好&#xff0c;复试分数90.24&#xff0c;电科学硕分数线84、信通83、专硕电子与信息74. 面试流程&#xff1a; 1&#xff1a;5min ppt的介绍。其中前2min用英语简要介绍基本信息&#xff0c;后3min可用英语也可用中文 介绍具体项目信息如大创、科研、竞赛等&#xff08…

AI指令百科全书:1000条AI指令,一次性全给你!

这是一位&#xff0c;国外博主哈桑 整理的&#xff0c;1000条ChatGPT实用指令&#xff0c;涵盖目前几乎所有的&#xff0c;主流提示需求。 全文超过40000字。 我把它们翻译成更适合大家理解的「中文版Prompt」&#xff0c;并根据具体的内容&#xff0c;拆解成一二级目录&…

Serlet API详解

目录 一、HttpServlet 1.1 处理doGet请求 1.2 处理doPost请求 二、HttpServletRequest 2.1 核心方法 三、HttpServletRespons 3.1 核心方法 一、HttpServlet 在编写Servlet代码的时候&#xff0c;首先第一步要做的就是继承HttpServlet类&#xff0c;并重写其中的某些方法 核心…

基于边缘智能网关的储充一体电站管理方案

在“2030碳达峰&#xff0c;2060碳中和”的目标下&#xff0c;我国持续加快推进能源转型&#xff0c;扩大新能源占比&#xff0c;全国各地都在部署建设光伏、储能、新能源汽车充电等应用。随着新能源汽车的广泛普及&#xff0c;充电站、充电桩的需求快速增加&#xff0c;行业也…

瑞芯微RK3568:Debian系统如何安装Docker

本文基于HD-RK3568-IOT评估板演示Debian系统安装Docker&#xff0c;该方法适用于RK356X全系产品。 HD-RK3568-IOT评估板基于HD-RK3568-CORE 工业级核心板设计&#xff08;双网口、双CAN、5路串口&#xff09;&#xff0c;接口丰富&#xff0c;适用于工业现场应用需求&#xff…

git:一、GIT介绍+安装+全局配置+基础操作

版本管理系统&#xff08;SVN和Git&#xff09;&#xff1a; 集中式版本控制系统&#xff08;SVN&#xff09; SVN是集中式版本控制系统&#xff0c;版本库是集中放在中央服务器的. 工作流程如下: 1.从中央服务器远程仓库下载代码 2.修改后将代码提交到中央服务器远程仓库…

基于VR元宇宙技术搭建林业生态模拟仿真教学系统

随着科技的飞速发展&#xff0c;教学方式也正在经历着巨大的变革。林业经济学元宇宙虚拟教学系统作为一种新兴的教学方式&#xff0c;为学生和教师提供了一个全新的、沉浸式的学习和教学环境。 森林管理和监测 元宇宙技术可以用于森林管理和监测。通过无人机、传感器和虚拟现实…

JavaScript的Web Worker

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ JavaScript的Web Worker⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量…

Goby 漏洞发布|Revive Adserver 广告管理系统 adxmlrpc.php 文件远程代码执行漏洞(CVE-2019-5434)

漏洞名称&#xff1a;Revive Adserver 广告管理系统 adxmlrpc.php 文件远程代码执行漏洞&#xff08;CVE-2019-5434&#xff09; English Name&#xff1a; Revive Adserver adxmlrpc.php Remote Code Execution Vulnerability (CVE-2019-5434) CVSS core: 9.0 影响资产数&a…

网络通信(套接字通信)(C/C++)

1.网络编程必知概念 1.广域网和局域网 广域网:又称外网、公网。是连接不同地区局域网或城域网进行计算机通信的远程公共网络。 局域网:在一定的通信范围内,有很个多计算机组成的私有网络就叫局域网。(这些计算机相互之间是可以通信的,但是不能直接访问外网(可以通过网线…