技术贴 | SQL 执行 - 执行器优化

本期技术贴主要介绍查询执行引擎的优化。查询执行引擎负责将 SQL 优化器生成的执行计划进行解释,通过任务调度执行从存储引擎里面把数据读取出来,计算出结果集,然后返回给客户。

在关系型数据库发展的早期,受制于计算机 IO 能力的约束,计算在查询整体的耗时占比并不明显,这个时候关注重点主要放在对于查询的优化。优化器的好坏,对于执行计划的优劣有着重要的意义,查询执行引擎的作用在数据库优化中对应等级是相对弱化的。但随着计算机硬件的发展,查询执行引擎也逐渐展现出他们的重要地位。

本篇博客结合 KaiwuDB 的部分源码和实例,介绍其如何充分发挥底层硬件的能力,优化查询执行引擎,从而提升数据库系统的性能。查询执行引擎是否高效与其采用的模型有直接关系,1990年,论文"Volcano, an Extensible and Parallel Query Evaluation System"提出了火山模型,这也是 KaiwuDB 查询执行引擎的基础。

一、火山模型/迭代模型

火山模型作为经典的查询执行模型被诸如 Oracle、MySQL 等主流关系数据库采用。该模型将关系代数中每一种算子抽象为一个 Operator(迭代器),每个 Operator 都提供一个接口 Next(),调用该接口会返回该算子产生/处理的一行数据(Tuple)。通过在查询树根节点自顶向下地调用 Next(),数据自底向上地被拉取处理,因而火山模型也称为拉取执行模型(Pull Based)。

图片火山模型

以一个两表连接的查询为例,让我们留意图中的第 ④ 步,Select 运算符。

调用 Next() 方法从其子运算符请求下一行,并检查它是否通过了筛选条件。如果是,则该行将返回到其父运算符;否则,将丢弃该行并重复该过程。

// RunFilter runs a filter  expression and returns whether the filter passes.
func RunFilter(filter tree.TypedExpr, evalCtx *tree.EvalContext)(bool, error){if filter == nil{return true, nil}d, err := filter.Eval(evalCtx)if err != nil{return false,err}return d == tree.DBoolTrue, nil
}

上述即 KaiwuDB 在处理行时进行过滤的函数,参数 Filter 类型为 tree.TypedExpr,意为一个通用表达式。也就是说,对于每一行,都会调用一个完全通用的标量表达式的过滤器。表达式可以是任何东西:乘法、除法、相等检查或内置函数,它甚至可以是由上述表达式组成的树。由于这种通用性,计算机在过滤每一行时都有很多工作要做,它必须在做任何工作之前检查表达式是什么,这与解释型语言的逻辑相同(与编译型语言相比)。

尽管火山模型简单、直观、易用,只需将 Operator 自由地组装,且每个 Operator 只关心自己的处理逻辑,执行引擎并不感知。但是,在执行过程中,迭代一次只处理一行数据,数据局部性差,很容易使 CPU cache 失效,并且调用 Next() 函数(虚函数)次数太多,开销较大,使得 CPU 执行效率不高。

二、算子融合

将经常出现的 Operator(如 Project 和 Filter)融合在其他 Operator 中能够一定程度上减少虚函数的调用,提高单个 Operator 的处理能力和数据局部性。以 KaiwuDB 的 tablereader 算子为例,在扫表时便能够对数据行进行过滤和投影,其 Next() 函数中实现了相关逻辑。

下图是 tablereader 算子 Next() 函数调用的简化时序图,可以看到,在读取一条数据进行处理时会判断 Filter 和 outputCols 决定是否进行 Filter 和 Projection 操作。
图片TableReader 算子 Next() 函数调用的简化时序图

下图展示了一条查询语句示例的物理计划,也可以看到在 TableReader 算子中对范围 Spans 和输出列 Out 进行了限制。
查询的计划示例
查询的计划示例

三、向量化模型

不同于火山模型按行迭代的方式,如下图所示,向量化模型采用批量迭代,在算子间一次传递一批数据。通过更改数据方向(从行到列),把从列到元组的转化推迟到较晚的时候执行,来更有效地利用现代 CPU。连续的数据有利于 CPU cache 的命中,减少 memory stall 现象;除此之外,通过 SIMD 指令一次处理多个数据,可以充分利用 CPU 的计算能力。
火山模型和向量化模型迭代数据的差异
向量化模型整体架构与火山模型类似,依然采用了拉取式模型。考虑一个具有 Id,Name 和 Age 三列的表 People, batch 将由 Id 的整型数组、Name 的字符串数组以及 Age 的整型数组组成,面对查询 SELECT Name, (Age - 30) * 50 AS Bonus FROM People WHERE Age > 30; 其向量化模型大致下图所示。
向量化模型
显然向量化模型与列式存储搭配使用可以获得更好的效果,但非列式存储也可以采用折中的方式来实现向量化模型。KaiwuDB 使用的是行存储引擎,在其向量化执行模型中,在底层 Operator 中实现了多行到向量块的转化,上层的 Operator 则以向量块作为输入进行处理,最后再由顶层的 Operator 进行向量块到行数据的转化。

除此之外,为了避免上文提到的火山模型下由于 Filter 所使用标量表达式的通用性带来的额外计算开销,在 KaiwuDB 的向量化执行模型中,每个向量化 Operator 在执行期间不允许任何自由度或运行时选择。

这意味着,对于数据类型、属性和工作任务的任意组合,都有一个专门的 Operator 负责工作。执行引擎从 Operator 链请求 batch:每个 Operator 从其子级 Operator 请求一个 batch,执行其特定工作任务,然后将 batch 返回到其父级 Operator。

因此对于示例查询 SELECT Name, (Age - 30) * 50 AS Bonus FROM People WHERE Age > 30; 实际向量化模型比上述的内容更复杂,具体如下图所示。
具体向量化模型
SelectIntGreaterThanInt Operator 在获取 People 表的 batch 后将选择所有 Age 大于 30 的值;然后,这个新的 sel_age batch 将传递给 ProjectSubIntInt Operator,该 Operator 执行简单的减法以生成 tmp batch;最后,这个 tmp batch 被传递给 ProjectMultIntInt Operator,该 Operator 计算最终的 Bonus=(Age - 30)* 50。

为了具体实现这些向量化 Operator,KaiwuDB 将流程分解为单个列上的紧密 for 循环。以下的代码段(有删减)实现了 SelectIntGreaterThanInt Operator 的部分功能。该函数从其子项 Operator 中检索 batch,并循环访问列的每个元素,同时将大于 30(p.constArg) 的值选中标记。然后,将 batch 及其选中向量返回给父级 Operator 进行进一步处理。这段代码虽然简单但却非常有效,for 循环迭代了一个 int64 的切片,将每个切片元素与另一个 int64 常量进行比较,并将结果存储在另一个 int32 切片中,从而实现了一个快速的循环。


func (p *selGTInt64Int64Const0p) Next(ctx context,Context) coldata,Batch {// In order to inline the templated code of overloads, we need to have a// 'decimalScratch' local variable of type 'decimalOverloadScratch'.decimalScratch := p.decimalScratch// However, the scratch is not used in all of the selection operators, so// we add this to go around "unused" error._ = decimalScratchfor{batch := p.input.Next(ctx)if batch.Length() == 0 {return batch}vec := batch.ColVec(p.colIdx)col := vec.Int64()var idx intn := batch.Length()if sel := batch,Selection(); sel != nil {sel = sel[:n]for _, i := range sel {var cmp boolarg := col[i]{var cmpResult int{a, b := int64(arg), int64(p.constArg)if a < b {cmpResult = -1} else if a > b {cmpResult = 1 } else {cmpResult = 0}}cmp = cmpResult > 0}isNull := falseif cmp && !isNull{sel[idx] = iidx++}}}if idx > 0 {batch.SetLength(idx)return batch}}
}

KaiwuDB 使用 kv 存储引擎 rocksdb 作为底层存储。通过从存储读取行后将行转换为列式数据的 batch,然后将这些 batch 送到向量化执行引擎中处理,对于处理大量数据时有可观的性能提升,但在数据量小时向量化是没有优势的,因为向量化的过程会带来额外的开销。

因此,面向行的执行模型可以为联机事务处理(OLTP)查询提供良好的性能,而向量化执行模式往往更适用于涉及海量数据的联机分析处理(OLAP)查询。KaiwuDB 在执行计划时会根据估计的 tablereader 输出的最大行数,与 SessionData 中的 VectorizeRowCountThreshold 字段比较来判断是否需要向量化执行。

KaiwuDB 默认开启向量化执行引擎,用户也可以选择关闭。关闭和开启向量化执行引擎可以通过 SET 进行设置,如下图所示。除此之外,使用 EXPLAIN(VEC)语句可用于查看查询的向量化执行计划。
通过 SET 设置关闭向量化执行引擎

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

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

相关文章

前端JS解构数组对象

// 3. 对象数组解构const arr [{username: 小明,age: 18,agw:19},{username: 小ha,age: 18,agw:19}]arr.map(item>item.age)//js结构数组对象console.log( arr.map(item>{return {aaa:item.age,bbb:item.username}}))

搜维尔科技:【软件篇】TechViz是一款专为工程设计的专业级3D可视化软件

在沉浸式房间内深入研究您自己的 3D 数据 沉浸式房间是一个交互式虚拟现实空间&#xff0c;其中每个表面&#xff08;墙壁、地板和天花板&#xff09;都充当投影屏幕&#xff0c;创造高度沉浸式的体验。这就像您的 3D 模型有一个窗口&#xff0c;您可以在其中从不同角度走动、…

bclinux aarch64 ceph 14.2.10 文件存储 Ceph File System, 需要部署mds: ceph-deploy mds

创建池 [rootceph-0 ~]# ceph osd pool create cephfs_data 64 pool cephfs_data created [rootceph-0 ~]# ceph osd pool create cephfs_metadata 32 pool cephfs_metadata created cephfs_metadata 64 报错 官方说明&#xff1a; 元数据池通常最多可容纳几 GB 的数据。为…

haproxy端口耗尽no free ports

用haproxy配置负载均衡时出现端口不足错误&#xff1b;后端服务连接一会高一会儿低&#xff0c;从0到1w、2w跳变&#xff1b;实际连接数为4w左右&#xff1b; haproxy[8765]: Connect() failed for backend 09e581: no free ports. 问题描述 在请求很少的时候&#xff0c;工作…

人工智能与大数据:驱动现代业务转型的双引擎

在当今数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;和大数据已成为驱动业务和技术创新的关键力量。它们的结合不仅重塑了传统行业&#xff0c;也催生了新的商业模式和服务方式。 AI与大数据在零售行业的应用 在零售行业&#xff0c;AI和大数据的应用已经成为提…

排序 算法(第4版)

本博客参考算法&#xff08;第4版&#xff09;&#xff1a;算法&#xff08;第4版&#xff09; - LeetBook - 力扣&#xff08;LeetCode&#xff09;全球极客挚爱的技术成长平台 本文用Java实现相关算法。 我们关注的主要对象是重新排列数组元素的算法&#xff0c;其中每个元素…

No208.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

echarts官网卡?

全网echarts案例资源大总结和echarts的高效使用技巧&#xff08;细节版&#xff09; - 掘金 drawnLine() {let myChart echarts.init(document.getElementById("grade"));// 绘制图表myChart.setOption({title: {left: "center",},tooltip: {trigger: &qu…

数字孪生智慧园区:大数据驱动下的运营管理革新

随着物联网、大数据、云计算等技术的飞速发展&#xff0c;数字孪生技术应运而生&#xff0c;它将物理世界与数字世界紧密连接起来&#xff0c;为各行各业提供了前所未有的解决方案。智慧园区作为城市的重要组成部分&#xff0c;通过数字孪生技术&#xff0c;可以实现更加高效、…

如何在 Windows 10/11 上高质量地将 WAV 转换为 MP3

WAV 几乎完全准确地存储了录音硬件所听到的内容&#xff0c;这使得它变得很大并占用了更多的存储空间。因此&#xff0c;WAV 格式在作为电子邮件附件发送、保存在便携式音频播放器上、通过蓝牙或互联网从一台设备传输到另一台设备等时可能无法正常工作。 如果您遇到 WAV 问题&…

数据库数据恢复—MSSQL报错“附加数据库错误823”如何恢复数据?

数据库故障&分析&#xff1a; MSSQL Server数据库比较常见的报错是“附加数据库错误823”。如果数据库有备份&#xff0c;只需要还原备份即可&#xff1b;如果无备份或者备份不可用&#xff0c;则需要使用专业的数据恢复手段去恢复数据。 MSSQL Server数据库出现“823”的报…

1.jvm基本知识

目录 概述jvm虚拟机三问jvm是什么&#xff1f;java 和 jvm 的关系 为什么学jvm怎么学习为什么jvm调优?什么时候jvm调优调优调什么 结束 概述 相关文章在此总结如下&#xff1a; 文章地址jvm类加载系统地址双亲委派模型与打破双亲委派地址运行时数据区地址运行时数据区-字符串…

理工ubuntu20.04电脑配置记录

8188gu无线网卡配置 首先下载github上的文件&#xff0c;进入文件夹 安装make命令 1. 查看usb无线网卡 sudo lsusb|grep 8188 2. 环境准备 sudo apt-get install git make build-essential git dkms linux-headers-$(uname -r) 3. 编译安装 git clone https://github.com…

敏感数据是什么?包含哪些?如何保障安全?

最近看到不少小伙伴在问&#xff0c;敏感数据是什么&#xff1f;包含哪些&#xff1f;如何保障安全&#xff1f;这里我们小编就给大家一一解答一下&#xff0c;仅供参考哦&#xff01; 敏感数据是什么&#xff1f; 敏感数据&#xff0c;是指泄漏后可能会给社会或个人带来严重危…

UE5、CesiumForUnreal实现加载GeoJson绘制墙体(Wall)功能(StaticMesh方式)

文章目录 1.实现目标2.实现过程2.1 实现原理2.2 具体代码2.3 应用测试2.3.1 流动材质2.3.2 蓝图测试3.参考资料1.实现目标 与上一篇以StaticMesh方式实现面类似,本文通过读取GeoJson数据,在UE中以StaticMeshComponent的形式绘制出墙体数据,并支持Editor和Runtime,在Editor下…

C#中.NET Framework 4.8控制台应用通过EF访问已建数据库

目录 一、创建.NET Framework 4.8控制台应用 二、建立数据库 1. 在SSMS中建立数据库Blogging 2.在VS上新建数据库连接 三、安装EF程序包 四、自动生成EF模型和上下文 1.Blog.cs类的模型 2.Post.cs类的模型 3.BloggingContext.cs数据库上下文 五、编写应用程序吧 我们…

流量分析(5.5信息安全铁人三项赛数据赛题解)

黑客通过外部的web服务器攻击到企业内部的系统中&#xff0c;并留下了web后门&#xff0c;通过外部服务器对内部进行了攻击。 目录 黑客攻击的第一个受害主机的网卡IP地址 黑客对URL的哪一个参数实施了SQL注入 第一个受害主机网站数据库的表前缀(加上下划线 例如abc_) 第一…

哔哩哔哩自动引流软件的运行分享,以及涉及到技术与核心代码分享

先来看实操成果&#xff0c;↑↑需要的同学可看我名字↖↖↖↖↖&#xff0c;或评论888无偿分享 大家好&#xff0c;我是一名专注于自动引流软件研发的技术专家。今天&#xff0c;我将与大家分享自动引流软件涉及到的技术与核心代码&#xff0c;希望能为大家提供一些有价值的参…

【postgresql】查看数据中表的信息

切换到postgresql数据库&#xff0c;各种不适应吧。 有个需求需要查询数据表的各种信息。 下面我们一起学习吧。 ●PostgreSQL: Documentation PostgreSQL: Documentation ●pg_namespace 存储名字空间。名字空间是 SQL 模式下层的结构&#xff1a;每个名字空间有独立的关系…

国际阿里云:无法访问ECS实例中的服务的排查方法!!!

操作场景 无法访问ECS实例中的服务可能有以下原因&#xff1a; 可能原因 排查方案 ECS实例的安全组未开放相应端口 检查ECS实例安全组规则 ECS实例中&#xff0c;该服务未启动/开启或服务对应端口未被监听 检查服务状态及端口监听状态 ECS实例内防火墙设置错误 检查ECS…