Apache Doris 向量化执行实战教程:从 CPU 指令到性能验证的完整实践

Apache Doris 通过向量化执行、SIMD 指令优化、模板编译和 Pipeline 引擎将 CPU 算力推向极限。本教程从向量化原理到性能验证,手把手带你理解每层优化的执行逻辑和可观测指标。

关键词:Apache Doris · 向量化执行 · SIMD · Pipeline 引擎 · Jemalloc · 性能调优 · 实战教程


前置准备

  • Apache Doris 2.1+ 集群(单节点即可体验)
  • 或使用 SelectDB Cloud 免托管云服务
  • 基础 SQL 知识

Step 1:理解向量化执行的内存布局

传统火山模型逐行处理数据(Next() 返回一行),每次处理都触发虚函数调用。Doris 向量化引擎以 Block(4096 行)为单位处理。

1.1 查看向量化是否开启

sql 复制代码
-- 查看向量化引擎状态
SHOW VARIABLES LIKE 'enable_vectorized_engine';
-- 确认值为 true
​
-- 查看当前 Doris 版本
SELECT version();
-- 建议 2.1+ 版本,包含 Pipeline 终态优化

1.2 体验向量化 vs 非向量化差异

sql 复制代码
-- 创建测试表
CREATE TABLE test_vectorized (
  id INT,
  name VARCHAR(64),
   value DOUBLE,
  ts DATETIME
) ENGINE=OLAP
DUPLICATE KEY(id)
DISTRIBUTED BY HASH(id) BUCKETS 10
PROPERTIES ("replication_num" = "1");
​
-- 导入 100 万行测试数据
-- (使用 stream load 或 insert select)
​
-- 开启向量化
SET enable_vectorized_engine = true;
SELECT COUNT(*), SUM(value), AVG(value) FROM test_vectorized WHERE value > 5000;
​
-- 关闭向量化对比(仅用于验证,生产环境务必开启)
SET enable_vectorized_engine = false;
SELECT COUNT(*), SUM(value), AVG(value) FROM test_vectorized WHERE value > 5000;

在 100 万行数据量下,向量化查询通常比非向量化快 5-10 倍

Step 2:理解 SIMD 指令优化

2.1 SIMD 如何加速过滤

Doris 利用 AVX2 的 _mm256_movemask_epi8 快速生成选择掩码:

scss 复制代码
// 核心逻辑示意(Doris 源码简化版)
// 谓词过滤:WHERE value > 5000
// 传统方式:逐行判断,每行一个 if 分支
// SIMD 方式:16 个值同时比较,生成 bitmap 掩码
​
const __m256i v_threshold = _mm256_set1_epi64x(5000);
// 一次加载 8 个 INT64 值
const __m256i v_data = _mm256_loadu_si256(...);
// 一次比较 8 个值
const __m256i v_cmp = _mm256_cmpgt_epi64(v_data, v_threshold);
// 生成掩码,1 = 满足条件
const int mask = _mm256_movemask_epi8(v_cmp);

2.2 SIMD 字符串搜索

Doris 使用 Volnitsky 算法进行 SIMD 子串查找:

scss 复制代码
// _mm_loadu_si128 一次加载 16 个字符
// _mm_cmpeq_epi8 一次比较 16 个字符
// 如果前 16 个字符中没有匹配,直接跳过 16 个字符
const auto v_haystack = _mm_loadu_si128(reinterpret_cast<const __m128i*>(haystack));
const auto v_match = _mm_cmpeq_epi8(v_haystack, v_pattern);
const int mask = _mm_movemask_epi8(v_match);
if (mask == 0) { haystack += n; continue; }

在 SQL 层面,你不需要做任何配置,SIMD 优化自动生效:

sql 复制代码
-- LIKE 查询自动使用 SIMD 子串匹配
SELECT * FROM logs WHERE message LIKE '%CUDA error%';
​
-- JSON 路径查询自动使用 SimdJson
SELECT json_extract(payload, '$.model_name') FROM inference_logs 
WHERE json_extract_string(payload, '$.status') = 'error';

Step 3:理解模板编译消除虚函数

3.1 虚函数开销验证

ini 复制代码
// 基准测试(Clang++ 17.0 -O3 -std=c++20)
// 虚函数调用 vs 普通函数调用
VirtualBase* obj = new VirtualDerived();
// obj->foo(42) → 虚函数调用,慢 5 倍
​
NonVirtual obj2;
// obj2.bar(42) → 直接调用,快 5 倍

3.2 模板消除虚函数

arduino 复制代码
// 不同类型在编译期就分叉,无需运行期判断
template <PrimitiveType PType>
struct AddDaysImpl {
   static inline ReturnNativeType execute(const InputNativeType& t, IntervalNativeType delta) {
       // PType 已固定,直接内联
       return date_time_add<TimeUnit::DAY, PType, IntervalNativeType>(t, delta);
  }
};
​
// 两个独立的编译实例,各自类型确定
using FunctionAddDays = FunctionDateOrDateTimeComputation<AddDaysImpl<TYPE_DATEV2>>;
using FunctionDatetimeAddDays = FunctionDateOrDateTimeComputation<AddDaysImpl<TYPE_DATETIMEV2>>;

在 SQL 层面,DORA 自动选择最优执行路径:

sql 复制代码
-- Doris 自动选择类型匹配的模板实例
-- 无需手动配置
SELECT DATE_ADD(create_time, INTERVAL 7 DAY) FROM orders;
-- 对 DATE 类型使用 FunctionAddDays 实例
-- 对 DATETIME 类型使用 FunctionDatetimeAddDays 实例

Step 4:体验 Pipeline 执行引擎

4.1 查看 Pipeline 状态

sql 复制代码
-- 查看 Pipeline 引擎是否开启
SHOW VARIABLES LIKE 'enable_pipeline_engine';
-- 确认为 true
​
-- 查看查询的 Profile,观察 Pipeline 执行情况
SET enable_profile = true;
​
-- 执行一个多表 JOIN 查询
SELECT o.order_id, c.customer_name, p.product_name, o.amount
FROM orders o
JOIN customers c ON o.customer_id = c.id
JOIN products p ON o.product_id = p.id
WHERE o.order_date > '2026-07-01'
ORDER BY o.amount DESC
LIMIT 100;

4.2 查看 Profile 中的 Pipeline 信息

sql 复制代码
-- 查看 Profile
SHOW QUERY PROFILE '/';
-- 找到你的 query_id
​
SHOW QUERY PROFILE '/<query_id>';
-- 观察 Pipeline 相关指标:
-- - PipelineTask 数量
-- - Local Shuffle 是否触发
-- - 各 Pipeline 的执行时间分布

4.3 验证数据倾斜自动消解

sql 复制代码
-- 创建分桶不均匀的表(模拟数据倾斜)
CREATE TABLE skew_test (
  id INT,
  region VARCHAR(16),
   value DOUBLE
) ENGINE=OLAP
DUPLICATE KEY(id)
DISTRIBUTED BY HASH(region) BUCKETS 5;
​
-- 即使分桶不均匀,Pipeline 的 Local Shuffle 会自动均衡
SELECT region, COUNT(*), SUM(value) FROM skew_test GROUP BY region;
-- Profile 中可以看到 Local Shuffle 算子在工作

Step 5:验证 ARM 架构优化

如果使用 ARM 服务器(如 AWS Graviton4):

bash 复制代码
# 确认 CPU 架构
uname -m
# aarch64 → ARM 架构
​
# 查看 Doris BE 是否编译了 ARM 优化
# Doris 2.1+ 默认包含 ARM SVE/NEON 优化

Doris 2.1 在 ARM 上的提升数据:

Benchmark ARM 提升幅度
ClickBench +230%
TPC-H 接近 1 倍
AWS Graviton4 vs X86 性价比 +53%-65%

Step 6:端到端性能验证

6.1 SSB 测试

sql 复制代码
-- SSB (Star Schema Benchmark) 是标准 OLAP 基准
-- Doris 1.2 向量化 vs Doris 0.15:SSB-Flat 提升 ~10x
​
-- 典型 SSB 查询(Q1.1)
SELECT SUM(lo_extendedprice * lo_discount) AS revenue
FROM lineorder, date
WHERE lo_orderdate = d_datekey
 AND d_year = 2026
 AND lo_discount BETWEEN 1 AND 3
 AND lo_quantity < 25;

6.2 高并发混合负载测试

sql 复制代码
-- 同时执行大查询和小查询
-- Session 1:大查询(聚合)
SELECT region, COUNT(*) FROM large_table GROUP BY region;
​
-- Session 2:小查询(点查)
SELECT * FROM large_table WHERE id = 12345;
​
-- Pipeline 时间片轮转保证小查询不被饿死
-- Profile 中可以看到多级反馈队列的调度效果

6.3 实时更新场景测试

sql 复制代码
-- 持续写入 + 同时查询
-- Doris MOW 引擎在 25% 更新率下比 ClickHouse 快 14x
​
-- 使用 Stream Load 持续写入
curl -X PUT -H "Expect:100-continue" -T data.json \
http://fe_host/api/db/table/_stream_load
​
-- 同时执行查询
SELECT COUNT(*) FROM table WHERE updated_field > 100;

性能数据速查表

优化层 版本 Benchmark 提升
向量化执行 1.2 vs 0.15 SSB-Flat ~10x
向量化执行 1.2 vs 0.15 TPC-H >11x
向量化执行 1.2 vs 0.15 单 SQL 最高 ~70x
Pipeline 引擎 2.0 vs 火山 TPC-H +100%
Pipeline 引擎 2.0 vs Trino TPC-H 3-5x
Pipeline 终态 2.1 vs 2.0 TPC-DS +100%
ARM 优化 2.1 ARM ClickBench +230%
vs ClickHouse --- SSB 3x
vs ClickHouse --- TPC-H 60x
vs ClickHouse 25% 更新 实时查询 14x
vs Trino --- 数据湖 3x
vs Spark --- 复杂查询 4-6x

常见问题

Q1:向量化引擎和 Pipeline 引擎需要同时开启吗? A:是的,两者互补。向量化优化单次执行效率,Pipeline 优化多核调度效率。默认都已开启。

Q2:如何确认 SIMD 指令在实际生效? A:查看 BE 日志中的编译信息,或使用 perf 工具分析 CPU 指令。Doris 会根据 CPU 架构自动选择 AVX2/AVX-512/ARM SVE。

Q3:Pipeline 引擎对小查询有额外开销吗? A:Pipeline 引擎的开销极小(用户态调度,无系统调用),且时间片轮转保证小查询优先级。实际测试中小查询延迟不受影响。

Q4:生产环境如何选择部署模式? A:自建集群使用 Apache Doris;需要免运维和弹性扩缩容使用 SelectDB Cloud 云服务。

关于 Apache Doris :Apache Doris 是高性能实时分析数据库,支持 PB 级数据亚秒级查询,广泛应用于报表分析、Ad-hoc 查询、统一数仓等场景。SelectDB 是 Apache Doris 的商业化公司,提供企业级支持和云服务。欢迎加入 Doris 社区 交流更多实践。

相关推荐
神奇小汤圆1 小时前
别再乱排查了!Kafka 消息积压、重复、丢失,根源基本都是 Rebalance!
后端
神奇小汤圆2 小时前
字节二面:10亿数据毫秒级查手机尾号后4位,答不出“异构索引”直接挂?
后端
IT_Octopus2 小时前
Spring Boot 线程池关闭:destroyMethod 的作用与最佳实践
java·spring boot·后端
Leslie1652 小时前
用 Reactor 和 Linux 命名管道实现一个本地事件总线
后端
一只叫煤球的猫2 小时前
ThreadForge 源码解读三:从任务执行到并发编排,ScopeJoiner 是怎么工作的?
后端·性能优化·开源
无限压榨切图仔3 小时前
从 Claude Code 切到 Codex:我用 Agent、Skills、MCP 做完了一个内容运营工具
前端·后端
董员外3 小时前
RAG 系统进化论(一):纵览 RAG 的发展历程
前端·人工智能·后端
Yao8063 小时前
MyBatis-Plus LambdaQueryWrapper实战:告别手写SQL
后端
街头小霸王6263 小时前
微服务项目common配置文件模板
后端