共计 2794 个字符,预计需要花费 7 分钟才能阅读完成。
目录
openGauss 数据库 SQL 引擎
openGauss 数据库执行器技术
一.openGauss 数据库执行器概述
二.openGauss 执行引擎
三. 高级个性介绍
Ⅰ. 编译执行
Ⅱ. 向量化引擎
openGauss 存储技术
openGauss 事务机制
openGauss 数据库安全
openGauss 数据库执行器技术
三. 高级个性介绍
这个章节咱们介绍下 openGauss 执行器外面几个高级个性,在介绍个性之前,先简略介绍下以后 CPU 体系架构里影响性能的几个关键因素,这些关键因素和其应答的技术形成了执行器里两个关键技术,编译执行和向量化引擎。
§ 函数调用:函数调用过程中须要保护参数和返回地址在栈帧的治理,解决实现之后还要调回到之前的栈帧,因而在用户的函数调用过程中,CPU 要耗费额定的指令来进行函数调用上下文的保护。
§ 分支预测:指令在古代 CPU 中以流水线运行,当处理器遇到分支条件跳转时,通常不能确定执行那个分支,因而处理器采纳分支预测来预测每条跳转指令是否会执行。如果猜想精确,那么流水线中就会充斥指令,如果对跳转猜想谬误,那么就要要求处理器丢掉它这个跳转指令后的所有已做的操作,而后再开始用从正确地位处起始的指令去填充流水线,能够看到这种预测谬误会导致很重大的性能惩办,会导致大概 20-40 个时钟周期的节约,从而导致性能的重大降落。这里能够看到提速形式一共有两种。是更精确的智能预测,然而无论如许精确,总会存在误判,另外一种就是从根本上打消分支。
§ CPU 存取数据:CPU 对于数据的存取存在显明的档次关系,在寄存器、CPU 高速缓存(CACHE)、内存的存取速度越来越慢,所承载的容量越来越大。同时 CPU 在拜访数据的时候也会遵循从快到慢的准则,比方 CACHE 中找不到的数据才会从内存中找,而这两者的访问速度差距在两个数量级。如果 CPU 的拜访模式是线性的(比方拜访数组),CPU 会被动将后续的内存地址预加载到 CACHE,这就是 CPU 的数据预取。因而程序如果可能充分利用到这个特色,将大大提速程序的性能。
§ SIMD:单指令多数据流,对于计算密集型程序来说,可能常常会须要对大量不同的数据进行同样的运算。SIMD 引入之前,执行流程为同样的指令反复执行,每次取一条数据进行运算。而 SIMD 能够一条指令执行多个位宽数据的计算。比方以后最新的体系结构曾经反对 512 位宽的 SIMD 指令,那么对于 16 位整型的加法,能够并行执行 32 个整型对的加法。
Ⅰ. 编译执行
在上一篇文章【如何把握 openGauss 数据库核心技术?秘诀二:拿捏执行器技术(1)】的表达式计算大节中,介绍了基于遍历树的表达式计算框架,这种框架的益处是清晰明了,然而在性能上却不是最优,次要有以下几个起因:
§ 表达式计算其框架的通用性决定了其执行模式要适配各种不同的操作符和数据类型,因而在运行时要依据其表达式遍历的具体后果来确定其执行的函数和类型,对这些类型的判断要引入十分多的分支判断。
§ 表达式计算在整体的执行过程中要进行屡次的函数调用,其调用的深度取决于其树的深度,这一部分也有着十分大的开销。
这两个外围起因,分支判断和函数调用同样在执行算子中也是影响性能的关键因素,为了晋升其执行速度,openGauss 引入了业界驰名的开源编译框架 LLVM(Low Level Virtual Machine)来提速的执行速度,LLVM 是一个通用的编译框架,可能反对不同的计算平台。
LLVM 晋升整体表达式计算的外围要点如下:
1)openGauss 内置的 LLVM 编译框架通过为每一个计算单元(表达式或者执行算子外面的热点函数)生成一段独特的执行代码,因为在编译的时候提前晓得了表达式波及的操作和数据类型,为这个表达式生成的执行代码将所有的逻辑内联,齐全去除函数调用。
比方对于上一篇文章【如何把握 openGauss 数据库核心技术?秘诀二:拿捏执行器技术(1)】中提到的表达式计算过程,openGauss 内置的 LLVM 编译为这个表达式生成了上面这样一段非凡代码。这外面曾经没有任何其余的函数调用,所有的函数都曾经被内联在一起,同时去掉了对于数据类型的分支判断。
Bool qual()
{
bool qual1res = 2 * w_tax + 0.9 > 1;
bool qual2res = w_city !=’Beijing’;
Return qual1res && qual2res;
}
2)LLVM 编译框架利用编译技术最大水平的让生成的代码将两头后果的数据存储在 CPU 寄存器里,让数据读取的速度放慢。
Ⅱ. 向量化引擎
在【如何把握 openGauss 数据库核心技术?秘诀二:拿捏执行器技术(1)】的概要介绍中提到了执行器的数据流动模式:管制流向下、数据流向上。传统的执行引擎数据流遵循一次一元组的传输模式,而向量化引擎将这个模型改成一次一批元组的模式,这种看似简略的批改却带来微小的性能晋升,如图 6 所示。
图 6 单个元组与向量化元组比照
其中的次要晋升起因能够应答下面介绍的 CPU 架构里影响性能的几个关键因素。
§ 一次一元组的函数模型在控制流的调动下,每次都须要进行函数调用,调用次数随着数据增长而增长,而一批元组的模式则大大降低了执行节点的函数调用开销,如果咱们设定一次一批的数量为 1000,函数调用绝对于一次一元组能缩小三个数量级。
§ 一次一批元组的模式在外部实现通过数组来表白,数组对于 CPU 的预取十分敌对,可能让数组在后续的数据处理过程中,大概率可能在 CACHE 中命中。
比方对于上面这个简略计算两个整形加法的表达式函数(其代码仅为了展现,不代表实在实现),上面展现了一次一元组和一次一批元组的两种写法:
一次一元组的整形加法:
int int4addint4(int4 a, int b)
{Return a+b;}
一次一批元组的整形加法:
void int4addint4(int4 a[], int b[], int res[])
{for(int i = 0; i < N; i++)
res[i] = a[i] + b[i];
}
一次一批元组的这个计算函数,因为 CPU CACHE 的局部性原理,数据和指令的 cache 命中率会十分好,极大晋升解决性能。
§ 一次一批元组的数据数组化的组织形式为利用 SIMD 个性带来了十分好的机会,SIMD 可能大大晋升在元组上的计算性能,还是以方才上述整形加法的例子,咱们能够重写上述的函数如下。能够看到,因为 SIMD 能够一次解决一批数据,循环的次数衰减,性能能失去进一步晋升。
void int4addint4SIMD(int4 a[], int b[], int res[])
{for(int i = 0; i < N/SIMDLEN; i++)
res[i..i+SIMDLEN] = SIMDADD(a[i..i+SIMDLEN], b[i..i+ SIMDLEN];
}
至此,openGauss 数据库执行器技术章节完结,下一章将开启 openGauss 存储技术的学习,未完待续 ……