向量化执行引擎是怎么玩的?

本文探讨了向量化执行引擎在现代数据库中的应用,对比了传统火山模型的优劣,并分析了向量化执行引擎如何通过批量处理、减少函数调用和优化CPU利用来提高性能。文章还介绍了CPU的处理特性,如流水线、乱序执行和SIMD,以及编译执行和代码生成技术在提升查询效率中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在比较前沿的数据库中,比如cilckhouse,polar-x,TDSQL,都提到了一个比较新的词汇,叫向量化执行引擎。

clickhouse

polarDB-X

tdsql-A

向量化执行引擎似乎已经成为了主流数据库的版本之子。

那么向量化执行引擎是什么东西,做了哪些优化,能有什么收益呢?我决定来分析一下。

传统数据库执行器

早期数据库受限于硬件水平,IO、内存和CPU资源都非常昂贵,所以大多数数据库的执行器都采用的是传统的火山模型(经典的Volcano 模型)。

火山模型又称 Volcano Model 或者 Pipeline Model。

该计算模型将关系代数中每一种操作抽象为一个 Operator,将整个 SQL 构建成一个 Operator 树,从根节点到叶子结点自上而下地递归调用 next() 函数。

例如 SQL:

SELECT Id, Name, Age, (Age - 30) * 50 AS BonusFROM PeopleWHERE Age > 30

对应火山模型如下:

其实非常好理解。

  • User:客户端。负责获取用户的sql,也负责发送给客户端sql的执行结果。
  • Project:垂直分割(投影),选择字段。对应于sql为:“SELECT Id, Name, Age, (Age - 30) * 50 AS Bonus”,接收子节点数据后,通过处理,得到需要返回给上层的结果值。
  • Select(或 Filter):水平分割(选择),用于过滤行,也称为谓词。对应于sql为:“WHERE Age > 30”,接收子节点数据后,过滤掉不符合条件的数据。
  • Scan:扫描数据。将数据从存储层拉到计算层。比如将People的表数据从磁盘拉到内存。对应sql为:“FROM People”

数据库执行器的发展

火山模型的优劣

早期数据库受限于硬件水平,IO、内存和CPU资源都非常昂贵,比如计算层的数据一多,内存容易爆掉,所以火山模型采用每次只计算一行数据的方式,极大缩减了内存使用量。

火山模型的优点:简单易用,每个 Operator 可以单独抽象实现、不需要关心其他 Operator 的逻辑。

Volcano模型简单灵活,火山模型将更多的内存资源用于IO的缓存设计而没有优化CPU的执行效率,为什么之前的数据库设计者没有去优化这方面呢?

当时的 IO 速度是远远小于 CPU 的计算速度的,那么 SQL 查询引擎的优化则会被 IO 开销所遮蔽(毕竟花费很多精力只带来 1% 场景下的速度提升意义并不大)。

这在当时的硬件基础上是很自然的权衡。

但现在今时不同往日,硬件性能大力发展,在大数据等现代环境场景下,火山模型的弊端逐渐显露。性能表现差强人意。当需要处理的数据量增大时,具有显著的缺陷。

火山模型的缺点:查询树调用 next() 接口次数太多,并且一次只取一条数据,CPU 执行效率低;而 Joins, Subqueries, Order By 等操作经常会阻塞。

执行器为了适应复杂的表达式结构,计算一条表达式往往需要引入大量的指令;对于行式执行来说,处理单条数据需要算子树重新进行指令解释(instruction interpretation),从而带来了大量的指令解释开销。

据论文 MonetDB/X100: Hyper-Pipelining Query Execution 统计,在MySQL执行TPC-H测试集的 Query1 时,指令解释就耗费了90%的执行时间。

究其原因。主要有如下几点:

  • 每次 next 都是一次虚函数调用过程是被动拉数据,编译器无法对虚函数进行inline优化,同时也带来分支预测的开销,且很容易预测失败,导致CPU流水线执行混乱。
  • Volcano Style的代码对数据的局
### 向量化执行引擎的工作原理与实现方式 #### 工作原理 向量化执行引擎的核心在于通过批量处理数据来提升计算效率。具体而言,它将传统的逐行操作转变为对固定大小的向量(通常为几百到几千条记录)的操作[^3]。这种方式可以减少控制流开销并充分利用现代 CPU 的 SIMD (Single Instruction Multiple Data) 指令集,从而显著提高指令级并行性内存访问效率。 此外,在数据库系统中,向量化执行引擎还涉及优化后的数据结构设计。例如,采用列存储的方式使得连续读取某一列的数据更加高效,这进一步增强了向量化技术的效果。 #### 实现方式 1. **数据划分** 数据会被划分为若干个固定的向量单元,每个向量包含一定数量的记录。这种划分允许后续操作以批处理的形式完成,减少了循环迭代中的分支预测失败等问题。 2. **SIMD 利用** 使用 CPU 提供的 SIMD 指令集可以直接在一个时钟周期内对多个数据项应用相同的算术运算或逻辑运算。这对于诸如过滤、投影等常见 SQL 查询操作非常有效。 3. **查询计划调整** 在某些场景下,传统火山模型优化器可能无法完全发挥向量化的优势。因此,部分数据库引入了新的物理属性矢量特性(Trait/Physical properties vector),用于指导更高效的执行路径选择[^4]。 4. **特殊功能支持** 针对复杂查询需求,比如带有 DISTINCT 的分组聚合函数,也需要特别考虑其实现机制。例如 openGauss 中针对此类情况提供了专门的设计方案,确保即使存在去重需求也能维持较高的运行速度[^5]。 ```python # 示例代码展示简单的向量化加法操作 import numpy as np def vectorized_addition(a, b): return a + b array_a = np.array([1, 2, 3]) array_b = np.array([4, 5, 6]) result = vectorized_addition(array_a, array_b) print(result) # 输出 [5 7 9] ``` 上述 Python 脚本展示了基本的向量化概念——即一次操作即可作用于整个数组而非单个元素上。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸟蜀黍

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值