Everything You Always Wanted to Know About Compiled and Vectorized Queries But Were Afraid to Ask

Andy这篇论文的题目很骚,好像他之前列的题目是最好的关于。。。的论文,被评委毙了,反正意思就是特别自信,特别牛逼。

执行器优化,是AP引擎的核心问题,对当然后续AP和TP的边界会越来越模糊,总之需要大量计算的引擎,执行器就会成为瓶颈

尤其是当前硬件的进化,导致原先成为系统瓶颈的IO已经慢慢不再是瓶颈,那么执行和CPU的瓶颈一定是后续主要待解决的问题

所有数据库的执行,都是基于执行树,

传统的方式都是自顶而下,Volcano模式,从顶往下依次调研next,tuple-at-a-time,这种方式对CPU不太友好,但是传统数据库的瓶颈在IO

自然,你也可以自底向上,data-centric模式,简单理解,就是batch processing模式,Spark处理数据的方式就是典型的例子,每个算子都一次性把所有数据处理完,把中间结果传给上层的算子

传统的方式为什么不用data-centric?

直觉的想想,这个方法没法直接用,尤其是对tp场景,我只需要查一条数据,但是你底层需要把所有的数据都处理一遍,并且要存储大量的中间结果,明显是无法接受的

但对于AP场景,因为AP场景往往需要扫描基本全量数据,所以这个时候你用Volcano就很低效了,所以明显data-centric更适合于分析场景

并且做些优化,那么data-centric模式就会产生比较好的效果,

codegen就是这样主要的优化方式,

传统的数据执行器,都是interpreter,解释执行,一个一个operator去执行;解释执行的问题是,大量虚函数调用,这个是非确定性寻址,对CPU非常不友好,因为CPU Pipline无法预判

codegen主要的优化就是把多个operator合并编译成一个可执行机器code,比如论文里面经常看到的词fuse,看着比较唬人,知道spark里面有stage的概念,一个意思,就是这些operator可以pipeline执行,不需要cache中间结果。这样就可以大大优化执行效率。

JIT,just-in-time,这是codegen的一种方式,就是在运行时编译,你说为啥一定要运行时编译,我提前编译好不行,当然可以,但某些情况下,比如用户提交的一个查询,一个udf,这个只有在运行时才知道,所以需要JIT编译,所以JIT只是codegen的一种形式,不等同于codegen

LLVM,Low Level Virtual Machine,可以理解成一套可定制的编译器框架,提供,IR,中间表示语言,理解成介于高级语言和机器语言中间的语言

为啥需要LLVM,直接用java或c++的编译器不行,可以但是一般通用编译器对于执行优化做的不行,所以你如果用通用编译器生成的机器码,效率不高

LLVM的中间表示,编程语言无关的,你在任何编程框架中,都可以调用sdk编写,并最终编译成优化过的机器码

那再回到volcano模型,到底什么是Vectorized,

其实说简单也简单,就是本来是next一个tuple,但现在next一组tuple

所以核心ideal就是amortization,每调用一次函数,处理的数据更多了,并且如果每次只处理一列数据,那么对于cpu cache更友好,所以Vectorize往往针对列存,但注意不是不能用于行存,只是列存天然适合向量化执行,向量化本身只是指bath执行

所以文中,对于Vectorize两个约束,

 给出的例子是,

向量化,常常提到SIMD,Single Instruction Multiple Data,这个是CPU指令的扩展,如果用上SIMD,那么向量化执行的效率会更高,但SIMD本身不代表向量化的全部

文中后续,实现了两种原型,Tectorwise和Typer,分别进行一系列测试,比较到底哪一种模式更好,结论是差不多

这个领域还不成熟,所以名词特别多,容易绕晕,这篇主要就是把概念澄清一下

各种技术间组合也不是固定的,data-centric是否可以用向量化,volcano是否可以codegen,是否有一个系统可以把所有方法集成在一起?拭目以待 

原文地址:https://www.cnblogs.com/fxjwind/p/12504805.html