作者介绍
josehu(胡翔),腾讯云数据库高级工程师,具有多年分布式数据库内核研发经验,主要负责和参与过高可用、数据导入导出、索引等相关模块的设计和开发。博士毕业于中国科学院软件研究所,加入腾讯后主要负责CDW PG数据库向量化执行引擎等相关特性的设计和开发工作。
1. 什么是向量化执行
向量化是指计算从一次对一个值进行运算转换为一次对一组值进行运算的过程。
1.1 从CPU角度看
现代 CPU 支持将单个指令应用于多个数据(SIMD)的向量运算。例如,具有 128 位寄存器的 CPU可以保存 4 个 32 位数并进行一次计算,比一次执行一条指令快 4 倍。
比如我们在内存当中有4个32位的int,传统的CPU不支持SIMD,进行计算时需要4次从内存中Load数据,再进行4次乘法计算,然后把结果写回到内存当中,这个过程同样要进行4次。假如CPU支持SIMD,就可以一次载入多个连续的内存数据,一次计算多对操作数以及一次写入多个计算结果。这样的话理论上会比传统的CPU快4倍。随着CPU的发展,现在大家常用的都是128位的SSE的指令,后面又多了256位的AVX指令,以及英特尔现在最新的AVX512的指令,一次向量化运算的一组值可以变得越来越多,效率会越来越高。但这不一定是线性的关系,但是能够保证一次对一组值的操作是更多更快的。
1.2 从数据库角度看
类似地,对于数据库里面的一个查询语句,其向量化执行是每次运算都对一组元组进行批量运算的过程。
数据库里面的查询执行引擎使用最为广泛的模型是火山模型,即迭代模型。上层算子每次通过调用一个next函数,从下层算子获取一个元组并进行处理,然后递归地调用下层算子去获取元组。一些特殊的算子需要从下层算子获取所有元组之后才能继续执行,比如需要构建hash table的算子(HashAgg、HashJoin)或需要元组排序的算子等。火山模型的优势在于实现简单,而且方便对输出结果进行控制,在过去磁盘IO是主要瓶颈的情况下具有很好的效果,但是不能充分发挥当前CPU的能力,CPU的有效率、利用率非常低。自上而下逐层地函数调用会造成大量的指令以及数据的cache miss。因此,很多数据库使用向量化或者编译执行等方法来解决上述火山模型导致的问题。
向量化模型与火山模型类似,但是每次next调用返回的是一组元组,这样就可以将函数调用的代价均摊到多个元组上,从而减少总体函数调用次数。另外,算子内部实现或者计算函数实现可以使用更加高效的方式循环处理一组元组,比如使用编译器自动循环展开或者手动编写SIMD指令等方式。需要注意的是,在实际的计算中