每次都需要解释大量指令?使用 PolarDB-X 向量化引擎

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 向量化引擎为PolarDB-X的表达式计算带来了显著的性能提升。

作者:君启




介绍


PolarDB-X是阿里巴巴自研的云原生分布式数据库,采用了计算-存储分离的架构,其中计算节点承担着大量的表达式计算任务。这些表达式计算涉及到SQL执行的各个环节,对性能有着重要的影响。为此PolarDB-X引入向量化执行引擎,为表达式计算带来了几十倍的性能提升。


传统数据库执行器的缺陷


现代数据库系统的执行引擎,大多采用一次计算一行数据(Tuple-at-a-time)的处理方式,并且需要在运行时对数据类型进行解析和判断,来适应复杂的表达式结构。我们称之为“标量(scalar)表达式”。这种方式虽然易于实现、结构清晰,但是当需要处理的数据量增大时,它具有显著的缺陷:


为了适应复杂的表达式结构,计算一条表达式往往需要引入大量的指令;对于行式执行来说,处理单条数据需要算子树重新进行指令解释(instruction interpretation),从而带来了大量的指令解释开销。据论文《MonetDB/X100: Hyper-Pipelining Query Execution》统计,在MySQL执行TPC-H测试集的 Query1 时,指令解释就耗费了90%的执行时间。


此外,在最初的Volcano结构设计中,算子内部逻辑并没有避免分支预测(branch prediction)。错误的分支预测需要CPU终止当前的流水线,将ELSE语句中的指令重新载入,我们将这一过程称为pipeline flush或pipeline break。频繁的分支预测错误会严重影响数据库的执行性能。


向量化执行系统


数据库向量化执行系统最早由论文《MonetDB/X100: Hyper-Pipelining Query Execution》提出,它有以下几个要点:

  1. 采用vector-at-a-time的执行模式,即以向量(vector)为数据组织单位。
  2. 使用向量化原语(vectorization primitives)来作为向量化算子的基本单位,从而构建整个向量化执行系统。原语中避免产生分支预测。
  3. 使用code generation(代码生成)技术来解决静态类型带来的code explosion(代码爆炸)问题。


向量化引擎为PolarDB-X的表达式计算带来了显著的性能提升。在下图中,横轴为向量大小,纵轴为吞吐量,不同标量表达式和向量化表达式的性能测试对比结果如下:


1.jpeg


case表达式性能测试对比结果如下:


2.jpeg




整体流程


PolarDB-X中,向量化表达式的执行分为以下几个阶段:

  1. 用户SQL经解析后,在validator中进行校验,推导和修正表达式的类型信息;这一阶段为向量化运算提供正确的、静态的类型信息;
  2. 在优化器形成执行计划之后,需要对表达式树进行表达式绑定,实例化对应的向量化原语,同时分配好向量下标,供运行时内存分配;
  3. 执行阶段,依据Volcano式的结构,自顶向下的触发执行向量化原语,并将向量作为运行时数据结构。


3.png



运行时结构


数据结构


在PolarDB-X向量化执行系统中,采用以下的数据结构来存放数据:


4.png


向量化表达式执行时,所有的数据都会存放在batch这一数据结构中。batch由许多向量(vector)和一个selection数组而组成。其中,向量vector包括一个存储特定类型的数值列表(values)和一个标识null值位置的null数组组成,它们在内存中都是连续存储的。null数组中的bit位以0和1来区分数值列表中的某个位置是否为空值。


我们可以用vector(type, index)来标识batch中一个向量。每个向量有其特定的下标位置(index),来表示向量在batch中的顺序;类型信息(type)来指定向量的类型。在进行向量化表达式求值之前,我们需要遍历整个表达式树,根据每个表达式的操作数和返回值来分配好下标位置,最后根据下标位置统一为向量分配内存。


延迟物化


selection数组的设计体现了延迟物化的思想,参考论文《Materialization Strategies in a Column-Oriented DBMS》。所谓延迟物化,就是尽可能地将物化(matrialization)这一过程后推,减少内存访问带来的开销。在执行表达式计算时,往往会先经过Filter表达式过滤一部分数据,再对过滤后的数据执行求值处理;每次过滤都会影响到batch中所有的向量。以上图中的batch为例,如果我们针对第0个向量设置 vector(int, 0) != 1这一过滤条件,假设vector(int, 0)中有90%的数据满足该过滤条件(选择率selectivity = 0.9),那么我们需要将batch中所有向量90%的数据重新物化到另一块内存中。而如果我们只记录满足该过滤条件的位置,存入selection数组,我们就可以避免这一物化过程。相应的,以后每次向量化求值过程中,都需要参考此selection数组。


向量化原语


向量化原语是向量化执行系统中的执行单位,它最大程度限制了执行期间的自由度。原语不用关注上下文信息,也不用在运行时进行类型解析和函数调用,只需要关注传入的向量即可。它是类型特定(Type-Specific)的,即一类原语只能处理特定类型。


向量化原语的主体是Tight-Loop的代码结构。在一个循环体内部,只需要进行取值和运算即可,没有任何的分支运算和函数调用。一个简单的向量化原语结构如下所示:


map_plus_double_col_double_col(int n,
double*__restrict__ res,
double*__restrict__ vector1, double*__restrict__ vector2,
int*__restrict__ selection)
{
  if (selection) {
        for(int j=0;j<n; j++) {
            int i = selection[j];
            res[i] = vector1[i] + vector2[i];
        } 
  } else {
        for(int i=0;i<n; i++)
          res[i] = vector1[i] + vector2[i];
  }   
}

注:*左右滑动阅览


其运算过程利用了selection数组,逐步对向量进行取值、运算和存值,如下图所示:


5.png


向量化原语带来了以下优点:

  1. Type-Specific以及Tight-Loop的结构,大大减少了指令解释的开销;
  2. 避免分支预测失败和虚函数调用对CPU流水线的干扰,同时也能有利于 loop pipeline 优化【论文引用】
  3. 从向量中存取数据,有利于触发cache prefetch,减少cache miss带来的开销。


我们为各种标量化表达式提供相应的原语实现,从而完成从标量到向量化的转变。例如将加法运算 plus(Object, Object) 针对不同操作数类型生成原语,包括plus(double,double),plus(long, long)等。


短路求值


在向量化原语的基础上,我们可以进一步对分支运算(也称为控制流运算 Control-Flow)进行短路求值(short-circuit calculation)优化,提升表达式计算的性能。


例如,case 表达式由n个when表达式、n-1个then表达式、1个else表达式构成。对于表达式


select case when a > 1 then a * 2
             when b > 1 then b * 2
            else a * b


其逻辑语义是:

  • 对于满足 a > 1 的向量位置,计算 a * 2;
  • 对于满足 a <= 1 and b > 1 的向量位置,计算 b * 2;
  • 对于满足 a <= 1 and b <= 1 的向量位置,计算 a * b;
  • 把所有位置的数值组合在一起形成新的向量,输出。


具有以下树形结构:


6.png


由于标量化表达式按照volcano结构编排,并提供了统一的next()的接口,case表达式必须执行完所有的子表达式a>1,a*2,b>1,b*2和a*b之后,将全部结果汇总到一起,最后做case语义处理。这种执行方式不能根据when表达式的处理结果及时终止计算过程,而是对全部子表达式无差别执行。


引入向量化执行器以后,我们可以设计短路求值来优化此问题,每一个子表达式需要被提供合适的selection数组,从而正确选择列中合适的位置来进行向量运算。设第i个when条件表达式接受的selection元素集合为S.png ,其输出的selection元素集合为R.png,也就是第i个then条件表达式接受的selection元素集合。那么满足 DENG.png,其中S.png是原始的selection数组中的下标集合。我们把求取selection元素集合的步骤称为substract selection,case运算的整个过程如下图所示:


7.png



总结


PolarDB-X向量化引擎利用原语(primitive)来构建表达式,以向量作为运行时数据结构。每种原语仅为特定类型进行服务,从而减少了指令总数;原语中的tight-loop结构不仅对CPU流水线十分友好,也允许CPU进行数据预取,并且避免分支预测。此外,一些优化如延迟物化、短路求值,进一步提升了表达式求值性能。


然而,从用户SQL到向量化执行之间,存在着一道巨大的鸿沟。我们需要解决以下几个重要问题:


1. 如何确定表达式的输入输出类型,并为SQL中的表达式分配合适的原语? 2. 每个原语需要使用不同的向量来进行输入和输出,如何为正确地为原语分配向量? 3. 每种原语仅为特定类型进行服务,那么我们必然需要为一个表达式配备大量不同的原语,来适应不同的数据类型。如何应对原语数量爆炸这一问题?


在下一篇文章中,我们将为上述问题的解决方案进行详细介绍。




【相关阅读】

PolarDB-X 面向 HTAP 的混合执行器

PolarDB-X 面向 HTAP 的 CBO 优化器

如宝马3系和5系:PolarDB-X 与 DRDS 并驾齐驱

PolarDB-X 存储架构之“基于Paxos的最佳生产实践”

PolarDB-X 私有协议:提升集群的性能和稳定性

技术解读 | PolarDB-X 分布式事务的实现

技术解读 | PolarDB-X 强一致分布式事务

PolarDB-X 一致性共识协议 (X-Paxos)

相关实践学习
Polardb-x 弹性伸缩实验
本实验主要介绍如何对PolarDB-X进行手动收缩扩容,了解PolarDB-X 中各个节点的含义,以及如何对不同配置的PolarDB-x 进行压测。
目录
相关文章
|
7月前
|
关系型数据库 分布式数据库 数据库
体验高可用云原生PolarDB MySQL引擎
本实验主要介绍如何在一台CentOS 7操作系统的ECS实例上,通过SysBench测试工具,体验云原生PolarDB MySQL引擎的高可用特性。
306 0
|
8月前
|
存储 Java 测试技术
深度优化 | PolarDB-X 基于向量化SIMD指令的探索
本文将介绍PolarDB-X对于向量化SIMD指令的探索和实践,包括基本用法及实现原理,以及在具体算子实现中的思考和沉淀。
|
SQL 存储 关系型数据库
「一份成本、两种引擎」-- Babelfish for RDS PostgreSQL发布
2022年5月16号,阿里云RDS重磅发布Babelfish for RDS PostgreSQL,兼容SQL Server生态版本,本篇文章从以下角度探讨Babelfish的方方面面: - Babelfish是什么 - 为什么使用PostgreSQL来实现 - Babelfish的架构 - 受众与场景 - 最佳实践 - Babelfish的未来发展 # Babelfish是什么 基于Bab
|
存储 关系型数据库 分布式数据库
《POLARDB云数据库分布式存储引擎揭秘》电子版地址
POLARDB云数据库分布式存储引擎揭秘
70 0
《POLARDB云数据库分布式存储引擎揭秘》电子版地址
|
关系型数据库 MySQL 分布式数据库
《PolarDB MySQL引擎重磅功能及产品能力盛大发布》电子版地址
PolarDB MySQL引擎重磅功能及产品能力盛大发布.ppt
89 0
《PolarDB MySQL引擎重磅功能及产品能力盛大发布》电子版地址
|
SQL Cloud Native 关系型数据库
「一份成本、两种引擎」Babelfish for RDS PostgreSQL发布
Babelfish for RDS PostgreSQL 重磅发布,阿里云 RDS 团队通过产品能力的提升,实现一份硬件成本两种引擎,帮助客户降低成本。
456 0
|
存储 SQL Oracle
PolarDB MySQL引擎重磅功能及产品能力盛大发布
希望通过本次演讲介绍PolarDB MySQL引擎的重磅功能及产品能力,最终可以实践到大家的工作当中。
365 0
PolarDB MySQL引擎重磅功能及产品能力盛大发布
|
存储 达摩院 Cloud Native
普惠三农,PolarDB Ganos引擎助力网商银行大山雀探索新型金融服务
探索农村新金融模式,网商银行大山雀卫星风控技术被IDC评为远程银行领先实践。大山雀后端核心系统——时空数据平台融合了云原生关系型数据库PolarDB的Ganos空天数据库引擎服务。Ganos是阿里云联合达摩院数据库与存储实验室共同研发的新一代位置智能引擎。PolarDB内置Ganos引擎,支撑大山雀中遥感、农业无人机轨迹等海量空天数据实现超融合一站式存储和管理,其中动态拼接数千张卫星图像仅需几秒钟,用户反馈至少节省50%的储存和加工成本,比传统大数据解决方案效能高出一个数量级。
普惠三农,PolarDB Ganos引擎助力网商银行大山雀探索新型金融服务
|
SQL 关系型数据库 MySQL
PolarDB-X 1.0-用户指南-自定义控制指令-SHOW PROCESSLIST指令与KILL指令
功能版本说明 当PolarDB-X版本号小于 5.1.28-1408022 时,PolarDB-X仅支持物理连接的 SHOW PROCESSLIST 与 KILL 功能,详情请参见老版本SHOW PROCESSLIST指令与KILL指令。 当PolarDB-X版本号大于或等于 5.1.28-1408022 时,PolarDB-X支持逻辑连接与物理连接的 SHOW PROCESSLIST 与 KILL 功能,请参见本文档。
188 0
|
SQL 关系型数据库 MySQL
PolarDB-X 1.0-用户指南-自定义控制指令-老版本SHOW PROCESSLIST指令与KILL指令
功能版本说明 当 PolarDB-X 版本号小于 5.1.28-1408022 时,PolarDB-X 仅支持物理连接的 SHOW PROCESSLIST 与 KILL 功能,请继续阅读此文档。 当 PolarDB-X 版本号大于等于 5.1.28-1408022 时,PolarDB-X 支持逻辑连接与物理连接的 SHOW PROCESSLIST 与 KILL 功能,请参见SHOW PROCESSLIST 指令与 KILL 指令。 获取 PolarDB-X 版本号,PolarDB-X 自助升级的方法以及更多的版本介绍请参见版本说明文档。
154 0

相关产品

  • 云原生分布式数据库 PolarDB-X
  • 云原生数据库 PolarDB