00:04
好,大家晚上好,欢迎参加今天晚上的这个DB见直播活动啊,我是今天的分享嘉宾,来自啊腾讯云数据库的那个胡翔,然后首先啊,咱们来测试一下这个直播状态啊,是否OK,然后大家啊看能不能能不能看到这个画面,然后听到这个声音啊,然后如果没有问题的话,就是在我们这个直播直播间里面打个666。好的,我看到有一些小伙伴已经回复了,非常感谢大家,然后呢,在分享之前啊,先跟大家介绍一下这个DB建这个数据库,嗯,论文解读这个直播系列啊,然后我们每期呢,将邀请这个学术界的一些专家,还有这个腾讯技术的一大咖,解读这个数据库基础技术啊,还有那个创新的一个趋势,然后让更多这个数据库从业者了解行业前沿技术热点,然后分享这个啊数据库技术的一个创新成果。
01:01
然后本期啊,我们本期这个直播,我们将重点介绍这个向量化执行的一些啊基本原理,还有一个相关实践实现,然后将从这个前沿技术和工程创新的角度来进行一个分享。然后按照惯例啊,我们这个本期直播还会设置一个抽奖环节,然后将会为中奖这个同学送上这个数据库技术丛书一套,然后我们会在呃分享结束后进行一个抽奖,然后欢迎欢迎大家这个认真听讲,积极提问,然后获取我们这个周边的这个礼品。好的,然后就开始我们这个啊分享,然后简单的介绍一下啊个人嗯做一下自我介绍,然后啊,我是那个腾讯云数据库高级工程师胡翔,然后博士毕业于中国科学院软件研究所啊后来加入了高华为高斯实验室,工作了几年,然后嗯加入到这个腾讯嗯以来主要是负责这个数据库量化,嗯执行引擎等相关特性的一个设计和开发工作。
02:06
好的,然后我们就可以。开始直奔主题,然后这次分享这个题目是消化执行的一个基本原理和相关实现,然后主要参考这个,嗯,一下这个论文,然后主要两部分吧,第一部分首先是来做一个这个论文的一个解读,然后第二部分就是结合我们这个T一个具体实践,然后然后来阐述一下,就是一个量化引擎是怎么来从头到尾来实现的啊。首先是这个论文简介啊,这主要这几部分吧,然后嗯,就是论文作者,呃,他他有一个发现就是说就数据库系统这个CPU这个使用率是比较低的,这个RC,也就是啊,这个每每周期指数啊,这个是比较低零点啊,然后呢,他就发现就是啊,传统我们使用这个火山模型啊,这个这种一次处理一个原主这种执行方式啊,就导致了比较大的这个解释执行的一个代价,然后就阻止了,就是可以允许这个CPU并行执行的这些这个编译优化,然后这些编译优化呢,对性能的影响是比较至关重要的。
03:15
然后呢,另外有就是。他研究了这个这个数据库啊,它是嗯,采用另外一种这个执行方式,相当于是一个化的一个执行方式,然后它可以一次处理完整的一个列,这样的话就避免了上次呃上上面这种问题。但是这个数据的这个全部嗯物化的话,相当于嗯,增加一个内存的一个,嗯嗯带宽的一个负担,然后进而就影响这也会影响CPU一个效率。然后呢,就是最终就是作者啊,相当于在两个模型之间找到了一个折中点吧,然后为带DB设计了一个新的执行引擎,叫做X100,然后使用这个量化执行这个方式,然后提高这个CPU,呃,这个使用率,然后也验证了这个。
04:03
性能提升比较显著。然后具体包括这篇论文,具体包括这呃五分五部分内容吧,首先就是详细的介绍了一些这个现在CPU的一些显著特征吧,特别是跟这个查询执行相关的,然后就是基于这个TCH,它是一个啊标准的这个测试,测试那个测试那个集吧,测试集合,然后基于呃一进行了一个性能profile,然后。啊,针对一个像标准数据库啊,还有D以及呃,就是这些数据库啊,做了一个嗯嗯,新的profile,另外还还对一个这个手写的一个程序。作为一个性能,一个基准。然后第三个是第三部分就是阐述了他,嗯嗯,新设计的这个X100架构执行引擎的一个架构,然后也给出了这个提高查询执行效率的一个方法啊,另外又额外介绍了一些这个啊,数据表示啊,索引还有更新啊等这些这个其他方面的种东西。
05:13
然后第四部分就是比较重要的就是相当于他做了一个实验,然后嗯,对比结果显示这个X100它的一个优化性能啊,另外最后就是一些相关工作一些总结。首先我们看这个CP是怎么工作的,这块就是呃,右上角这个图啊,它就列了一个十年内的一个C一个发状态吧,然后我们可以看到就是也是越来越快的,然后当时应该是零五年的论,然后当时也是比较这个摩尔定律。相当于就是。CPU这个经济,呃,CPU这个经管这个数目啊,每隔两年也是,嗯,会增加一倍的,然后。我们看就是底下这条线,相当于是一个晶体管的一个长度吧,然后。
06:00
就是相当于每隔两年就是有一个一点倍,1.4倍的一个一个减少吧,然后相当于整个这个,嗯,容积的话是有两倍的一个提升。然后中间这条线啊,它表示的就是使用了另外一种技术式的这个CPU,它这个性能得到了更大的一个提升,这个技术就是这个pipeline的一个技术,它具体指的呢,就是它把一个指令啊划分成多个阶段,然后这样的话,这个多个阶段之间就可以这个进行并行了。然后这个带来的一个提升还是比较可观的。然后我们可以看右下角啊,这个有两个图啊,左边这个图实际上就是一个简单一个拍拍烂啊,然后它有划分成了五个阶段吧,然后我们可以看到就是中间就是。这些指令执行的时候,中间就这个啊,啊,不同指令的一个不同,这它就可以进行一个并并行了啊。然后这个拍烂的话,实际上它的运行是受一些条件进行约束的,嗯,最主要两个影响因素就是一个是依赖关系,再一个就是分支,分支这个预测,然后依赖关系指的就是说呢,就是如果一个指令啊,它会依赖前一个指令一个结果,然后它相当于就必须等待前一个指令执行完之后才能这个放入这个拍烂,这样的话相当于他俩是不是独立的,这样的话就相当于这个就必须有一个多余的等待。
07:26
动作就是不能不能,嗯,这个变化力度会会降低啊,再一个就是第二个就是刚才说的那个,呃,分支预测啊,然后就是实际上就是说就CPU在遇到分支的时候会,嗯。怎么来处理啊,就是它会相当于会。对将要执行这个分支进行一个预测,然后把这个预测的一个动预测这这个分支这个动作放到这个拍烂里面,但是如果这个预测失败的话,实际上之前执行这个拍烂都会进都进行一个废弃,相当于这个也会对这个拉的效率有一个很大的影响。
08:03
这是这是两个影响因素。然后再一个就是CPU还有这个一个技术,就是超标量这个多个排,这个这种并行,它实际上就是可以允许这个多个指令这个并行,从而达到这个FC大于一这个效果,然后这个下面这个右下方这个图实际上就是这样一个例子,相当于两个指令可以。同时运行啊。就是C这些一些特征的一个介绍。然后其实我们这边编程的时候,其实不不需要特别关注哪些啊,指令是独立的,哪些是相关的是吧,然后实际上这些工作是通过这个编译优化自动来实现的啊,然后这块就是说。编译优化里面有一个最比较重要的这个优化技术吧,就是peline,它实际上就是把一个循环里面多个迭代进行一个啊啊拍peline,然后允许它那个多次迭代进行一个并发一个执行啊,这个能极大提高这个嗯,一个简单这个lo这种执行效率吧啊。
09:15
然后我们可以看左下角这个例子,然后上面是相当于是一个顺序执行的一个例子,它这个循环它也相当于有也有相类似的,有有三个阶段吧,比如说就三个步骤吧,然后三次迭代的话,我们如果顺序执行的话,相当于就是九个。九个嘛,我假设一个stage代表啊,执行时间是一个的话,就是有个周期,然后我们通过编译优化的话,实际上就是。把之把它组成组成那个排的形式之后,嗯,我们假设它那个指令之间是相互独立的话,就可以达到比如说下面这种下下图这个这种效果,实际上我们就是五个周时钟周期就可以完成整个这个三次迭代位的。
10:01
啊啊,这个这个这个目的啊。这个相当于提升了将近一半的一个效率啊。然后有一些特定的,嗯C实际上也会做一些特定的优化吧,比如说这C他会主动会把指令进行一个划分,然后把它,比如说把相互依赖的这个指令,嗯拆解成不同的,呃拆解到不同的排发里面,这样就可以嗯分别进行一个并发。然后这个是比较独特,他自己独有的,然后其他的一些CPU的话,嗯。就是用的可能就是比较通用的这个乱序执行这个能力,他实际上指的就是CPU自己需要承担一部分调度的任务,他把一些独立的啊指令给嗯给摘出来,然后放在这个排发里面。但是这款CPU的话是没有是是相当于是用了一个一个一个划分,然后这样带来效果就是减轻了它这个。
11:05
拯救的一个负负担嘛,它可以把精力更多的投入到这个pipeline里面,相当于嗯,能更加提高这个pipeline的并行能力吧啊。然后还有就是他也对分支预测做了一个优化,就是他相当于把那个if then else,这个else这两个分支的话都都要。嗯,都要执行一遍,然后后面嗯。继续执行的时候,就会就会根据结果,就是那个那个结果来确定把哪个结果给,嗯,把之前哪个分支结果给抛弃掉,这也是一个优化。对对,这可能是比较旧的C,但是也是较通用技术,目前的话C也会会有类似的应用。然后我们就看一下右边这个图吧,这个这个右边这个图实际上就是嗯,研究了这个分支预测对这个性能一个影响吧,然后我们看这两个CPU的表现,底下这个是速龙,这个是比较嗯通用的这个普通的呃一个CP。然后可以看一。
12:17
然后这个嗯,Circle是相当于就是一个简单的一个嗯查询,然后带了一个VR条件。然后在它那个危害条件这个列啊,它是均匀分布在零到100这个数值啊,这个这个区间内的,然后我们就啊,根据他这个。这个大X这个值,然后就可以。相当于呃,看就是来来来来设置一下这个查询这个筛选率啊。然后我们可以看到这前面两条线啊,也就是这个速溶这个结果啊,它比如说这个方框这个代表的是,呃,原来这个带分支这种啊,带分支的这个就是咱们普通的这个编编写程序这个方式啊,然后底下这个这种方式,实际上是把这个分支给去除了,他把这个条件,嗯。
13:09
啊,付给了一个布尔值,然后底下就是呃数组这个,所以嗯,这个序号。增加的时候相当于对这个值做一个加法啊,这相当于就把这个条件给去除了,但是这个指令数会增加,对。然后回到这个图上啊,然后这个速龙它这个方块的这条线,它这个。在。选择率比较低,或者是选选呃筛选率比较高,这个情况下它的效率都是嗯比较高的,就是它的时间是比较短的,然后在中间这个位置,就是它筛选率比较中间这个位置的话,它这个消耗时间嗯是比较比较多的,也就是说它实际上是分支预测这个。误判率会比较多。对。然后看看那个这个叉号这个条线啊,它是指的这个底下这个去除这个if条件这种这个实现版本,像它这个就比较稳定吧,他因为他也没有分支,所以它这个一直是一条比较直的一条线啊。
14:15
然后我们就看底下这另外一款这个CPU的话,它都是的啊,这这就表明就是他自己这个,嗯,刚才介绍了这个自己独有的一些优化就生效了。然后反而是在那个。就第一个分支这种带分支这个版本,它这个性能是更更好,对,就是刚才也介绍了这个不带分支这个它指数会更高嘛啊。就是有一个,嗯,有一点点不同,对。然后这个下来就是还有一部分就是说这个CPU,它那个芯片上,它那个catch,这个对CPU整个这个性能发挥有一个什么的影响,这个影响还是比较大的,有些研究也是表明这块这个影响是特别是对数据库这个系统啊影响是非常大。
15:08
然后也有一些算法,包括像开始对齐的一些数据结构,还有这个限定开始上的一些算法,就是也是能极大提升一个性能的。然后我们也从右边这个图也能看到啊,就是距离CP越近,肯定是计算速度越快嘛,然后啊,像延迟的话,存延迟都是这个的,这个20倍或者是200倍,这个差距还是很大的,然后尽量嗯,如果能嗯将个计算都集中在这的话,实际上它也是可以有利于个发挥CPU的实际这个算力。对,然后就是刚才介绍这么多,就主要是一个是这开始命中率,再有一个是分支的数目,还有这个分支预测是否能成功,还有就是这个指令是否这个相互之间这个独立,这些都。
16:01
对这个CPU这个性能带来很大的影响吧。然后CP,嗯,像数据库这种,嗯,就当时CPU,当时据库的一些CPU使用率啊,都接近于嗯,零点是零点就比较低,低然后低于其他一些系统,比如说像可可学计算的一些系统啊,就是能达到二这种啊,然后他就指出啊,就相当于嗯嗯这时库不应该有这种表现吧,就是有很大提升空间吧啊然后特别是对这个O场景啊,针对于这个包含这个大数据啊,还有一些这个计算复杂计算这种场景啊,就是。应该期望能达到更好的一些,嗯,表现吧,啊,然后特别指出了,就是需要特别充分利用好这个CPU的一个排并行能力,然后本这篇论也主要是围绕这个,嗯,就提这个排并行这个来来来展开的,后面也是围绕这个,嗯作为一个优化的一个目标。
17:04
然后第二部分就是他就。选取了T,然后测试里面的一个一作一个研究对象吧,然后做了一个性能,然后深入研究了一下,就是性能瓶颈到底在哪。然后这个语句就是嗯,就是包含就是图图中这块啊,然后它实际上就是对一个表做一个一些嗯计算,还有一些那个聚集计算,对。然后。啊,它这个嗯几乎是扫描所有数据啊,这个filter其实没有,嗯筛选掉多少这个数据,然后嗯计算呢,包含像嗯加减法,还有一乘法,然后另外就是一些这个具体函数啊sum,嗯,Average,还有count这种啊,然后另外还有一个比较特殊的就是它这个分组件啊,就是两个列,它都是单词节的一个字符,所以它这个分组的情况啊,实际上就是嗯两个字节的一个组合,就是6536,就最最多是那么多情形。
18:14
然后后续它就是针对于这个啊corry做了一些性能分析,然后分别在像一些马,像这些传统数据关系数据库,还有像那个这种,嗯嗯,通过这个固化实现的这个数据库,还有就是嗯。一些这个手写程序,然后嗯,做了一个性能,一个性能测试。嗯,首先就看就是这里面是主要是以MYCQL这个为例啊,它嗯,作为传统一个关系型数据库,然后这个执行都是严格按照这个关系代数来实现的,然后具体的执行模型就是火山模型,火山模型这个迭代模型相当于就是呃,简单来讲就是上层算子啊,迭代的地柜的这个,呃呃,调用下层算子,然后每次获取一个元素,然后进行处理啊,然后这种。
19:11
嗯。这种方式,这种执行方式,然后还有一个就是说这种传统数据库上,它这个实现的话,实际上就是。嗯,自由度还是比较高的,就是它的关系代数的自由度,嗯比较高,嗯代的参数比较多,然后这样的话就需要就是一个比较通用的一个实现,就比如说表达式计算的话,这样的话它要要实现一个就是呃处理表达式收益场景情形的这种解释执行器,这个相当于就会更复杂一些。啊,然后的话。右边就是他,嗯对做了一个嗯嗯性能嗯profile吧,然后第一列是他那个累积的一个。呃,累计的一个这个CPU这个使用率。
20:03
然后第二列是相当于是它本身有的这个,嗯嗯嗯,CPU。然后啊,不是CPU就是它占有的那个比例。然后第三个第三列就是它那个函数的那个函数调用,然后第四个就是这个函数对应的这个呃,指令数,还有就是第五列就是它那个RBC。然后我们可以看到啊,就是嗯,他这里面给出了一个发现,就是说就所有的这个实际的这个工作啊,就占了这个整个呃,整个语句执行时间的一个一小部分啊,这里面主要看这个加加粗的这这几部分啊。然后。可以看一下,就是它一个是百分嗯百分之三点多2.9这些啊,实际上就是只是占了10%吧,总共占了10%,然后嗯进一步分析哈,发现就是其他的像28%就嗯创建这个探测气表,另外还有就是嗯,大部分都花费在这个消耗在这个原组解析啊,数据拷贝啊这些嗯通用的一些,嗯一些那个代价上啊。
21:21
然后。其他像素啊,八分管理啊,这些银行因素反正也比较小,对,然后另外就还有一个发现,就是说就是。这个实际的计算效率啊,比如说它里面有一个像加法这种计算效率和和这个CPU它本身提供能力啊,也是差异比较大的,也就是说就是比如说完成一个,嗯。Float类型的一个加法的话,它跟那个C,它用这个跟C。这块分析的原因啊,就是主要是他那个。因为是一次处理一个元组嘛,然后就没法,嗯,对进进行这个烂这个优化,然后相当于这个。
22:09
一次处理一次元组,一个元组的话,也会增加这个,嗯,那个函数的一个调用次数,这样的话就相当于就把这个CPU这个执行效效率给降下来了啊。然后的话,像其他数据库就是,嗯,可以看一下,就是前面这个下面这个图,其他数据库像这个DBMS这个还有。还有底下这个。底下嗯,底下这些其实都是呃,十秒或者20秒以上的这些嗯值,然后分析也是嗯,也是这个原因原因造成的。然后另外第二个就是呃,对那个DB这个这个执行执行引擎进行了一个呃。然后首先介绍一下这个,简单介绍一下这个P啊,它实际上是也是一个存的一个数据库,然后相当于把数据这个存划分了,然后嗯逐列存储,然每列这个存储形式就是一个它它它成为一个形式啊。
23:16
然后他这个,但是查询语言就是ML,然后它是可以。处理多个输入的这个BAT,然后输出一个这个。嗯,对,这是它的一个代数语言,然后这块嗯,额外说一下,就是它这个自由度是比较低的,也就是说他这个。嗯,相当于是对。呃,特定的数据类型,特定列都特定数据类型都做了一个那个呃区分,也就是说不是那种之前说到那种通用的类型了啊。这样的话,其实是能能能能减少一些那个解释代价啊。然后最终的结果就是右边这个图。
24:00
就是他确实这个右边。嗯,前前两前四列吧,前四列就是分不同的那个,呃。呃,数据量的一个对比,然后前两列是1G的啊,嗯嗯,后两列是这是相当于减少了不少,然后它一个执行时间,还有一个就是带宽的使用量。然后第第五列吧,第五列这个是一个应该是一个内存那嗯。啊,结果结果集的一个。一个啊,这应该是一个内存,内存一个占用情况啊,它是以兆为单位的,然后第六页这个应该是结果集啊,可以看到啊,就是首先一个就是说。没有那个刚才说的那个问题了,就是执行效率比较低这个问题。它这个具体执行计算的这些,嗯,这些调用啊,实际上都能达到这个占比能达到99%了啊,比其他数据库都要高。
25:03
啊,但是呢,还有一个问就是带来问题,就是它这个之前也介绍了,它是采用了一个是一个物化模型吧,然后相当于中间结果,嗯,就是。嗯,相当于把下层算子的一个结果都都会进行一个物化,这样的话就造成内存一个相当于一个堆积吧,相当于造成一些嗯。内存带宽也会受很大的影响,你看右边这个图里面啊,就是占用内存也是比较多的,然后。这个就是进而就会影响一个效率了,CPU效率这个通过这个前四列的一个对比也可以看到啊,就是它那个带宽这个一个对比啊,就在稍微大一点数据量这个S等于一,也就是1G,这个数据量它能达到带宽能达到四百五百啊四百五百这样,但是这个数据量减少之后啊,实际上它的带宽会嗯变了大了很多啊,大了很多,比如说刚才嗯说到那个雾化那个结果那个问题就在于GB这个嗯上体现的比较明显啊。
26:12
就是这个带宽受限了之后,这样就影响这个CPU的效率,看它的时间实际上嗯,在较小的这个数据量上呢,也有了一个更更大的一个提升吧啊。然后。另外就是一个,嗯,在一个基准程序上的一个奔驰,然后这个基准程序实际上把就是涉及的列都作为一个参数,然后。嗯,并添加了这个。就是它是一个数组表示嘛,然后并添加这个这这个关键字,这个意思就是告诉编辑器啊,它这个数组里面的这个元素都是嗯独立的都不相关的,这样呢,就方便那个编辑进行优化。然后还有就是利用了它这个group这个列这个数据的一个特征吧,就是他刚才提到的就是都是单字节的这个嗯字符,然后就是用数组来表示的啊,就是这个哈希本来是呃需要建立哈希表,但是它这块是直接用数组来来表示这个。
27:17
的一个一个,嗯,几何的啊。啊,另外还有一些子表达式的一句话,就是功能子表达式的一句话啊,然后这个结果呢。看一下这前面这个结果,这个这个结果实际上还是。嗯,有有很大提升,就是相比于其他的一个,嗯嗯已有的一些事项,但是嗯跟后面这个。但是跟后面这个嗯,差100比呢,还是差100会更更大一些,这个也就是说它超过了这个基准的一个性能,然后就是后面就就这块儿是怎么做到的,然后我后面就是通过嗯嗯,后面这个文章就详细介绍这个差一板这个一个一个具体一个实现。
28:12
然后它就是一个相当于是一个量化查询的一个,然后设计目标就是嗯,主要就是为了达到一个更高的一个CPU利用率,然后嗯,实现这个一个比较可扩展的一个代码,再一个就是针对这个底层存储规模进行一个可以可以进行伸缩啊。然后他就为了嗯,达到这个性能这个目标啊,那他就考虑了整个架构中这个可能出现的一些瓶颈的一些嗯位置啊,啊,比如说像磁盘IO啊,它就设计设计了这个比较高效的顺序,顺序那个数据访问啊这种这种。比如说来嗯列式存储,然后嗯主要解决这个,嗯解决嗯嗯多余的这些数据存储这个代价,然后也可以降低这个带宽的一些要求啊。
29:08
另外就是基于这个历史存储,也可以做一些轻量级压缩啊,进一步减少的一个带宽。另外就是对嗯内存,内存实际上跟嗯嗯磁盘一样,也是采取了这个劣势内存这个组织形式,然后也是目的是减少这个内存的一个占用啊。然后另外就是对catch,这个catch是在这里面是至关重要的,它是嗯,通过。嗯,把这个数据嗯组织成这个vector这个形式,然后把vect能够嗯完全放在catch,然后使得计算呢都嗯在这个catch内进行,这样的话就减少于其他的像memory一些交互啊啊这样就是能提高这个计算一个效率。也不必考考虑这个带宽的一些问题啊。
30:01
另外就是针对于C的话,就是它使用对于这个嗯,据库里面的一些操作,还有或者是子啊,使用这个量化,然后来实现。就让他这块就是相当于来方便。编辑器把它优化成这个烂这种高高高效代码。啊,右边就是一个示意图了,就是上面这个就是。是那个D啊,然后下面这个就是整整体一个更直观的一个结构啊。我们可以看到就是它这个执行引擎这块啊,实际上就是处理的这个单元都是一个方块,也就是代表一个向量,就是向量力度来处理的,然后这些嗯,向量呢,也是能够直接放到这个catch里面啊。
31:02
那也是做了一些开始的计算。然后是查询语言,这块跟嗯,之前那个M不太相同的,就是它可以生成多个向量,之前那个只能生成一个B啊,这块可以生成多个,然后可以作为嗯,就是比如说上层算子的一些一个输入啊。然后我们看右右上角这个图啊,就是它这个语法是怎么写的,就是上面是一个标准的语语句啊,它实际上就是Q1的一个简化的一个版本,然后写成下面这个,呃。这个100,它那个代数的一个形式啊。然后他这个执行流程啊,实际上还是跟之前那个活山模型那个烂那种方式是类似的,但是也是但是不同的就是它是以那个为处理单位。那我们可以看右下角这个图啊。
32:01
首先它包含就是几个算子吧,就是sc select啊,然后project跟,然后我们看SC的话,实际上就是从们DBBT里面就获取多个输入列对应的一个啊,这里面有三列吧啊,然后。Select它这块创建了一个辅助的一个相当于一个数组吧,就selection它用来标记嗯,哪些组是满足这个位此嗯条件的。对,他做了一个标记。然后这个数组的话,实际上对后面上面这些计算也是有很大影响的。因为他实际上没有把比如说你筛选出来数组进行数据的一个拷贝啊,重新一个编排,他还是按照相当于按照原来输入嗯进行嗯向上的一个传递,这样的话,上面的一个计算的话,其实跟可以基于原来的一种嗯输入,然后再加上这个select做一个进一步一个叠加计算啊,这样证明是。
33:08
嗯,效率是更高一些啊。然后回过头来,我们就接着看这个project,实际上就完成了一些嗯,表达式计算,然后为最终这个计算做一些准备吧,然后他刚才也提到,就也是用到了这个select啊。相当于。嗯,之前被筛选掉的那些原组啊,是没有必要在这里面做计算的啊。然后最后就是那个agg了,Agg计算这块就主要是包含。两部分啊,两部分吧,啊,一个是这个欧哈希表,再一个是做一个。被积极计算啊啊,另外还有一部分,还有一部分就是相当于最后一个结果输出了啊,然后做呃,构建哈希表,计算哈希位置的时候,实际上它也是要参考这个selection,另外就是做agg计算也是类似的啊,都要参考这个,嗯,这个这个数组。
34:10
然后这就是呃X1它的一个执行流程啊,我们看就是跟原来这个嗯嗯,火山模型其实整体流程是比较类似的,然后是多了一些嗯,辅助的一些数组啊,再一个就是相当于它那个处理力度啊,从原一个元组变成了嗯一个。这样相当于就是。一个是说嗯,调用函数调用次数变得少了很多,再一个就是单个计算的时候就可以,嗯用编译优化这种方式来,嗯进行了一个优化,就是批量的处理这个多元组啊,这样效率把把CPU的效率能提升的更高一些啊。然后。这它的一个代数形式啊,我们就大概看一下吧,这个还是比较特殊的,跟那个标准的这个SQL语言啊。
35:06
嗯。然后就是比较重要的这个化语,也就是相相当于他。那个怎怎么量来进行一个批量计算的,批量快速计算的。然后。另外是个例子啊,我们可以看一下,这个是一个double类型的一个数据啊,呃,做一个呃加法,然后它一些函数参数,包括这个select,这个实际上跟刚才那个select VE selection vector是类似的,就是有一个选选择性的一个辅助速度啊。然后的话。如果就是它这个所有的函数都会包含这个这个这个这个参数啊,如果它不为空的话,然后我们就参考这个嗯,这个数组,然后得到那个有效的那个,那那个嗯嗯圆组位置,然后对对它做一个加法,然后这个循环来做一个加法啊,然后底下就是不但筛选这个数selection这个数组的啊这就是更为简单,这这块就是一个简单的一个呃,然后做加法。
36:15
嗯,这个呃实现呢,首先说就是它是针对于每一个数据类型都有一个单独实现,就省去了这个组解析这个动作了,因为它这个圆组,嗯,这个列的类型是已知的。啊,再一个就是它一个每一个嗯嗯输入啊,都是一些向量,这些向量都可以完全放入到这个开始里面做计算啊,啊这个是也是。就是提高这个计算速度的,另外的这个就是这些。这些简单循环循环它是可以直接这个优化成这个排烂这种执行方式的啊。然后的话,它这些向量化原语啊,它这个生成也不是那个全是写的,这个应该是,呃,通过这个模板来自动生成的,这边也给了一个例子啊。
37:07
一个。嗯,加法相当于如果是数据串字符串的话,相当于做一个连接啊。然后另外就是还提到了一个组合化原引一个一个东西这块它实际上是也是一种方式,可以提高这个,进一步提高这个执行的一个效率。它这个原理就是说呢,就是比如说嗯,原来你做一个加法,可能两个操作数先做了一些,呃,数据的加载,然后后面就是数据的写入,然后中间才是一个一条加法的一个指令,这个这个数据的加载写入这个太高了。然后我们这边做了一个,呃,他们这边是做了一个组合的话,相当于实际工作做的更多了一些,这样的话相当于相当于是把嗯,两边两头的那个数据加载和写入这种代价给均摊了啊。
38:02
嗯。这样也是可以提高这个执行效率。另外就是数据存储,数据存储这块啊,他这个也嗯也简单的罗列了一下,就是列式存储,然后嗯列存,嗯每列单独存储嘛,嗯但是嗯这这种是一般是有更新啊删除这个代价,比如说就是更新一行的话,可能会涉及修改多个列文件吧,这个就嗯它是通过这个也是比较经典的,就是通用的一些方式吧,通过一个德结构来解决。相当于啊,比如说这个的话。嗯,看右边这个图啊的话,它是直接,嗯把这个。这个。然后的话,实际上他并没有在原来这个数据上做一些,嗯嗯,直接做一些增加啊,是直接放在了另外一个。
39:09
德尔塔这个结构的一个区域啊。相当于这块是直接用一个存的方式来存储的啊。然后update的话,实际上就是嗯,用的这种加的这种。执行方式。然后另外还有就是一个调查,就是相当于把呃,调查结构区域,嗯这些。嗯,组啊,合并到原原来这个存上去。另外还有就是也也会有一些这个索引信息啊,就是包括像这个汇总的这个局部的一个最大最小值,然后用于做数据的一个筛选啊,这些都是比较通用的一些这个的一个实现方式。然后下面一部分就是一个实验结果的一个对比了,然后我们就看一下,嗯,它一个是跟X100跟那个ML做一个对比,然后。
40:07
不同的处理器上,然后不同的那个。数据量都就明显比比那个要强不少。然后的话。嗯,对。然后我们也在那个他他也在那个100做了一个Q1上做,做了一个那个新的profile,然后我们也看到了,就是它这块,就之前说到那个,嗯,那个问题实际上也是解决了,它这个带宽还是比较高的啊,然后嗯,内存占用的话。嗯,少了很多啊。另外他这块啊也指出来了,就是他有些列啊,直接用的这个,嗯。
41:00
0.5这个类型做了一些优化啊。这是嗯,这个莫奈DB100的,嗯,这个结果。然后后来后面又对那个嗯向量的一个大小做了一个嗯测试吧,就是不同向大小对性能一个影响,然后从一到这个是四兆吧,然后的话可以看到啊,中间在大概1000左右这块,嗯,对这个性能是最好的。然后过大过小的话,肯定都是,嗯不是最优的一个结果,比如说11这种实际上就是原有的那种,嗯,一次处理一个原组那种方式啊,它这个代价是它这个效率是比较低的啊。然后。对,然后这个四四兆这个就是最大值这块相当于就是原有的那个M这种全部物化的这种方式了啊,它这个效率嗯,相比S100也是也是不如它的啊,然后这块就是说这个大小这个选择啊,它这个过大过小都不是很合适的,过大的话相当于就是嗯。
42:11
就没法开车,就会有一些额外的这个从那个其他从内存里面读取入数据的一个代价,一个就是说。嗯,过小过小的话,嗯,实际上就是跟原来那火山模型是类似的了,就没法做一些变异优化,然后无法发挥这个CPU的变化能力了,而且的话,函函数的调用次数也会增加很多,对,就是实际的工作这个占比就会变小。然后这块,嗯,就是论文做了一个总结,就是它实际上工作就是基于原有的这个经典的火模型,还有这个物化模型做了一个,呃,优化做了一个折中啊,然后得到了一个性能极大提升。然后嗯,原有这个火山模型呢,它就是一次处一个呃,一理一个圆,然后比较大的这个解释执行代价,然后阻止了一些这个关键的变异优化。
43:09
然后像雾化模型,像摩DML这种雾化模型的话,它是可以让CPU高效运行的,但是它又造成内期内存的这个密集型这种问题啊,内存的带宽会受限。啊,就是向量化这种方式的话,就是选择就是向量这种能够直接放到catch的这种,嗯嗯,这种这种力度啊,这种大小周围力度啊,进行一个批量计算,然后可以解决上述这两个问题吧啊。实验验证也有了一个数量级的一个提升。然后论文情况就到这里,然后是呃,我们那个T课刚才也相当于有一些,嗯。嗯,具体一个实现,然后我可以看一下。就是如何来实现这个现代化执行引擎,然后这块列取了四个主要方面吧,嗯,一部分是那个,呃,第一个就是现代化执行一个框架,再一个就是现代化一个数据数据结构,再一个是一个,呃,具体的一些算子实现啊,最后就是一个具体的一些函函数实现。
44:16
然后它这个执行框架,实际上就是负责这个现代化执行,以及计划的一些这个生成和执行啊,以及就是现代化计划跟分现代化计划的一些兼容。然后消化这个数据结构呢,就是主要是为了这个,嗯嗯,在内存里面,在就是准确的说应该是在开始里面设计合理的这个啊,组织形式啊,尽可能的使用这个。啊,开开这个资源,减少内存拷贝啊,然后算子实现就是需要对原有算子进行改造嘛,然后。按照的原则就是把它呃复杂的一个处理流程拆解成小的一个循环,然然后做一些简单操作,这样便于这个便于优化成这个高效程序。
45:03
然后另外就是这个函数实现了,就是跟算子实现实际上是类似的,然后还包括一些这个表达式计算框架的一些调整吧,然后还有就是。嗯,实际上就是这些计算函数化,嗯,可以通过CD这种显示的这个嗯指令来进行一个量化的一个优化啊。然后我们逐个看一下吧,就是嗯嗯,我们这个执行框架它。首先就是现代化计划生成的方式啊,就是我们实际上是采用比较贪婪的一个方式吧,我尽可能把计划中径里面设计的这个算子都转换成这个相化执行的方式啊啊。然后不支持的下滑这种的计划节点的话,我们就可以通过在上面加上一个行转列限量行转向量的一个算子,也就是说在这块嗯做一个转换,然后。相当于把它的输出从一个一一个一行元组变成了一个向量啊,这样的话就可以继续支持上层算子的一个向量化执行。
46:09
然后右边就是一个简单例子啊,原有的就是一个比较简单一个经典那个那个火车模型执行过程啊,就是上层算子调用next,然后每次从获取一个进行一个进行一个处理啊一个处理。右边这个向量执行的话,实际上嗯,最大区别就是每次获得的,嗯,方法的话,每次获得的是一个向量啊,然后每个算子内处理的单位也是一个向量啊。然后是呃化执行的一个数据结构,然后这块嗯主要是呃原则,有两个原则吧,一个是嗯,就是尽可能把它存在靠近CU这个位置啊,比如这个开始这块。然后再一个就是列式存储列式组织形式啊,后面对单个列进行快速计算啊。
47:06
然后这个原来嗯,原来这个圆组啊,我们这个实际上是通过这个嗯一行来表示的,这个top slot就是代表一行元组,然后为了便于一些化,我们就把它改造成一个嗯,嗯包含多个元组的一个结构,这里面是叫slo,然后它实际是简单的把嗯组合并起来做一个分就。嗯。嗯嗯,那个叫垂直划分,就是相当于把数据做了一个垂直划分,然后每一列,呃,数据的话是放在一起的啊。然后它这一列叫实际上就是叫做是列销量,这里面是来表示的。然后这个tablelo它还包括一些原信息啊,好说啊,列这种啊,然后列下来的话,进一步我们可以拆解出来,嗯,包含一个也是包含列数据啊,包括行数含有列描述信息啊,再一个就是。
48:09
一些那个数组,像数组数组啊,一个是呃,一个是数组的话,是用来标记这个这个元组的一些信息啊,这些啊,然后外流组是来存储那个具体的值的。然后。嗯,这个buffer实际上是,嗯,内存的一个挂载位置啊。然后这是因为6Y6它那个大小它是。嗯,他的那个嗯,结构是嗯,有些数据是没法存,直接存在上面的,比如说一些非正常的一些数据。然后这样就就需要申请一些八块来存储啊,然后就是我们这块也是相当于对定和不定这个数据类型做了一些嗯做出嗯分别做了一个处理吧,啊电场直接就放在这个外流速组里面,然后电场的话,然后我们要申请这个嗯buff,然后。
49:08
然后再把这个嗯,这个上的数据位置,然后再写到这个速度上去。然后这块内存的话也是可以快速复用。嗯,第三第三个部分就是算子实现啊,这块主要列,嗯主要是也是类似的吧,就是嗯原则就是拆解,然后嗯拆解成这个多个小循环,简单小循环,然后方便这个编辑器进行一些优化。然后再一个就是一些原则,就是减少分分支和数据依赖啊。然后这边举了两个例子啊,两个算子吧,两个比较重要算子哈希G跟这个哈希join啊,看一下怎么来实现这个算量化改造的啊。首先啊,你看这个图啊,这个嗯,实际上是一个也是一个简化版的Q1,然后。
50:04
这两列做分组,然后做了两个A操作啊,然后首先就是我们把输入的一个元组向量输入是一个向量啊,然后嗯,在这个向量基础上批量计算出哈希值,然后就是第一步,然后进而还有就是对应这个八的值,就它那个哈希table一个链那个手地啊。然后的话。然后的话,下一步就是构建这个哈希表了,然后嗯的话是采用这个opening这种冲突处理方式啊,相当于如果冲突的话,就继续找下一位置进行判断,那我们可以看啊,有些就是如果你发现就是当前这个位置是空置的话,我们就创建这个哈金。就是一个呃位置,创建一个位置,然后如果匹配的话就直接嗯。直接把这个海这个地址给保存下来啊。
51:02
然后有些是冲突的话,我们就找下一个位置,然后再继续判断,嗯,直到匹配位置啊,这样的话,最终嗯结果就是说嗯,我们把这个组都插入到这哈表里面了,然后也获取了每个元组对应的一个哈,嗯,另外还有一个就是有些嗯。嗯,就是table,它内存占用达到一定限制的话,它这个元组需要下盘的啊。嗯,这是第二步整个构建哈希的一个步骤,然后第三步就是计算这个A,嗯,计算聚合函数了,然后再把这个。就是包括像萨跟做一个计算,然后再把这个结果更新到之前保存的那个上啊。接着就是嗯嗯,最后就是那个嗯。
52:01
电力焊气表,然后把这些嗯结果拼接成这个列向量,然后嗯拼接成这个向量这种形式,然后进行输出啊,然后最后一步,如果还有这个下盘数据的话,实际上我们要把当前这个table进行重置,然后重新构建table,然后相当于再把上面流程再执行一遍啊。这是整个这个哈,销量化的一个执行一个流程。嗯,接着就是join算子这个向量化,嗯这块,嗯,也看右边这个例子啊,就是很简单一个join,然后两个表进行一个join。然后嗯,首先的话,对干这个内表哈,这个得到的元组向量也是要做一个批量的这个哈希值的计算,以及哈希8K的这个值的一个计算。然后第二步就是对内表进行一个嗯,Table的一个构造啊,然后呢,就是。就到嗯到外表,然后对表扫描到圆组,嗯去那个上做一个探测,但是呃之前呢,需要嗯也是需要先批量的计算哈基值跟那个哈西8K的值啊嗯,然后就是相当于也是得到一个向量,然后对嗯。
53:19
对,可以可以对应到那个上的一个对应的位置,也是一个相当一个形式,然后再做一个批量的一个匹配操作,如果匹配的话,我们就把它进行一个标记,然后不匹配的话,我们就相当于去找下一个位置,进行下一步的一个匹配。最终结果就是把所有匹配的一个组,然后拼接成量,然后输出出来啊。这是算子的一个向量化时间。啊,最后是嗯嗯,函数的一个实现啊这块,嗯。我们具体时间的时候啊,就是没有增加新的类型啊,只是嗯,对那个原有那个版本的函数做了一个嗯改造,然后具体执行的时候,相当于消号,执行的时候要用替换进行一个替换。
54:13
对,然后右边是一个例子吧,就是这块是相当于是一个IN4类型的,IN32类类型的一个嗯嗯判等,然后左边是比较简单,就是一个攀等,然后右边的话,实际上我们输入相当于都是一个外列限量。然后。它是这样一个形式的啊,然后需要注意的就是我们左边这个实际上就是也是嗯,它它这个判空判空这个逻辑实际上是在函数外面的啊,然后我们这边嗯,右边这个是嗯,因为他要对每行进行判空嘛,所以嗯有这点不太一样的地方啊这块嗯。这块涉及的那个函数会比较多,对我目前是嗯把所有的,嗯,几乎所有的这个数据类型,通用的数据类型,这上面的函数都都已经支持啊。
55:05
然后最终就是一个总结,还有一个展望吧,啊,然后这次分享主要是通过一篇有关这个现代化执行的经典论文,然后介绍了一个量化执行的基本原理,然后通过然后结合这个T的一些实现,详细阐述了这个量化实现过程啊。然后嗯,后面的话,我们嗯仍在,嗯就是继续提升这个查询,查询这个效率,包括对这个算子,这个量化算法进行更加深入的一个优化,然后还有就是通过CD啊这个显示质量,提高这个向量化的一个嗯水平。另外就是编译执行,嗯,也是这个解决这个类似问题一个手段吧,然后特别是这个表达式计算解析啊,这种也是比较有效的啊,这工也在进行中。然后期待下次带来更多的优化吧啊。行。
56:00
然后我的分享大概内容就是这些,看大家有没有什么问题。啊,我已经看到了,就是后台嗯,有反馈这个问题。第一个问题是说火山模型有这么大的缺陷,为什么还有那么多数据库在用啊,啊这个可能得说一下这个背景啊,因为这个火山模型提出时间比较早啊,因为当时可能那个CP它不是瓶颈啊,当时那个。磁盘比较慢,所以呢,就是CPU这个额外代价,嗯,不会显得那么突出,再一个就是说,就是火山模型本身它是比较简单的,然后嗯,只要实现那个,比如说那个嗯,三个接口吧,啊B跟N加这个中间有一个。
57:01
啊,它是实现起来比较简单,就是算子可以单独来实现,然后相互之间也可以就是嗯,很简单的进行组合啊,所以就是一些通用的,嗯,数据库都是大部分都是采用关系型数据库啊,都是采用这种火山模型这种方式。然后还有一个问题是。显示的调用英特尔的,嗯,AX指令集吗?啊,这个这个应该就是说的那个CD啊,那个那个嗯。指令他这个是际,我们我们目前的话是有使用,但是可能不是那么多,有些像哈,像那个。还计算还有一些像嗯字符串的,嗯嗯字符串的一个,嗯,比对的时候是用一些那个啊C指令的啊。
58:01
然后刚才也提到了,就是我们下一步的优化目标也是在一些尽可能多的一个函数里面,增加这个CD指令的一个使用啊。然后问题三是说向量化和C什么关系啊啊,这个刚才就是,嗯。嗯,也也说到就是C币其实是量化是一种吧,它是可以理解为是一个显示的一个实现一个方式吧,然后向量化其实包含就是咱们这个,咱们这次分享,嗯,着重说到了这个编译这种优化,实际上它是就是自动的一个优化方式嘛,然后CD话,实际上就是一直相应的就是说一个手动的需要手写,嗯嗯,手写那个指令的这种方式。刚才那个小伙伴提这个问题,这个A应该,嗯,这这就是其中的一种,呃,指令集啊。
59:02
对,然后相当于的话就是向量化,如果需要进一步提升的话,肯定是要需要这个,嗯,实现更多的CD指令啊。嗯,我再看一下。嗯,德尔塔处理增三改的情况下,Select语句如何处理?嗯,这个是要做做扫描的,就是嗯,就是原来列那个尔数据扫描。否则是不全的嘛啊。嗯,第五个问题,向量化定义是否应该包含CD啊这块,嗯,刚才也详细介绍了啊,这个实际上是是包含的,但是咱们这个文章它主要集中在自动那个编译化,对后面我们如果有机会的话,我们就是。
60:04
嗯,可以再继续做这个C些相关的,然后看后。如用做进一步。对t base里面实现了吗。所以刚才啊,我们实际上就是。啊,就是TT贝斯啊。然后最后一个问题是哈希join或者是聚合计算完哈希值是并插入到哈希表里面吗?嗯。这个肯定是顺序,顺序来来做的就是。它实际上也是顺序来做的啊,但是这块实际上把整个过程可以进行进一步拆分,就是。就把相互独立的那个模块进行一个拆分,然后相当于每一部分独立完成,这样的话就是每一个循环,比如说每一个循环嗯,能更。
61:08
更负责,嗯,就是负责一小块任务,然后嗯,能通过优化能做到一个,嗯,更大的一个优化吧,啊。锁的话,这里面不不设计锁,因为顺序顺序的话,这块是没有设计锁,然后并发的话,实际上是另外一套啊,嗯,就是。执行那块确实是是有所的,因为有些是涉及到那个哈西table的一个共享啊,但是我们嗯。就非并行并发的模式下,是不不涉及到锁。嗯,大量增删改,大量增删改实际上就不是o lab这个场景啊啊。就是这个问题,小伙伴问题是说大量增删改的场景下都需要扫描,那存性能不会降低很多吗?
62:07
嗯,这个是确实有这种问题啊,这是。实际上这个德尔塔这个结构就就是为了处理这个有这种改这种场景这个嗯。这种这种就处理这种场景吧,啊,但是如果有特别大量的感的话,肯定这个存还是不太适合的,它主要还是做一些O场景的一些计算。但是我们实际上是支持行列缓存的,就是针对不同场景的话,我们可以选择不同的一个存储形式。好吧。然后。行。时间原因。我们就。然后问题的环节就到这吧,啊到最后啊,嗯,然后非常感谢大家这个聆听啊,啊参与到我们这个活动啊,然后欢迎大家这个扫描这个二维码,然后关心我们,关注我们这个,嗯,腾讯云数据库这个后续的一些活动。
63:03
好的,嗯,然后那个我们下期见。
我来说两句