土法炼钢 · 系统与基础设施

【列存引擎内核】向量化执行引擎

文章导航

分类入口
databasestorage
标签入口
#clickhouse#vectorized-execution#block#processor#pipeline#simd#volcano-model#24-lts

目录

存储层把 Part 读成 列向量第 2 篇);执行层必须在 batch 上算,否则函数调用与 cache miss 吃掉列存带宽优势。ClickHouse 官方 Architecture 明确:operations dispatch on arrays (vectors or chunks of columns)

本文拆解 Block、IProcessor pipeline,并对照 PG 执行器火山模型。版本:24.x LTS


一、为什么需要向量化

Volcano:每算子 next() 返回一行 → 虚函数 + 分支多,CPU 流水线难满。

向量:一次处理 \(N\) 行(max_block_size,常见 65536)→ filter 生成位图、aggregate 批量 update。

MonetDB/X100(CIDR 2005)系统论证了 vectorized + cache-conscious 对 OLAP 的必要性;ClickHouse 属同一设计谱系。

flowchart LR
  VOL[Volcano 逐行] --> CH[ClickHouse 逐 Block]
  CH --> SIMD[SIMD 友好]

二、Block 与 Column

Blocksrc/Core/Block.h)= 列名 + ColumnWithTypeAndName 数组 + 行数。

类型 头文件 说明
ColumnVector<T> ColumnVector.h 数值 POD 数组
ColumnString ColumnString.h 偏移 + chars
ColumnNullable ColumnNullable.h null map + nested
ColumnLowCardinality ColumnLowCardinality.h 字典列

IColumn 接口:clone、insert、filter、permute 等,算子间传递 ColumnPtr


三、IProcessor 与 Pipeline

IProcessorProcessors/IProcessor.h):

PipelineExecutor 多线程调度 ready 处理器,减少全局同步(官方 Architecture Processors 节)。

flowchart TB
  SCAN[MergeTreeSelect] --> PRE[Prewhere]
  PRE --> FIL[FilterTransform]
  FIL --> EXP[ExpressionTransform]
  EXP --> AGG[AggregatingTransform]
  AGG --> OUT[Output]

四、读存储:MergeTreeSource

MergeTreeSelectProcessor / read pool 从 Part 读列 → 组装 Block → 下游算子。与 第 5 篇 衔接。


五、Filter 与 Project

FilterTransform:对条件列求值 → UInt8 过滤 mask → IColumn::filter 裁剪各列。

ExpressionTransformExpressionActions 将 AST 编译为对列的循环(非常量折叠时)。


六、Aggregate

AggregatingTransform:按 key 列 hash,批量更新 AggregateFunction 状态(非逐行 transition)。GROUP BY + 高基数时内存受 max_bytes_before_external_group_by 等限制。


七、与 PG 执行器对照

机制 PostgreSQL ClickHouse
驱动 ExecutorRun 循环 ExecProcNode PipelineExecutor
数据 TupleTableSlot Block
表达式 EEO opcode ExpressionActions
Hash Join 逐行 build/probe 批量
并行 parallel worker 部分节点 pipeline + read pool

PG 向量化改进(如 bulk read)存在,但 OLTP 兼容约束下仍以行为主;ClickHouse 默认即 batch


八、Settings 与调优

Setting 含义
max_block_size 单 Block 行数上限
min_insert_block_size_rows insert 最小 batch
max_threads 执行线程
compile_expressions LLVM JIT 表达式(视版本)

九、实验说明

本环境无 ClickHouse。读者可用:

EXPLAIN PIPELINE SELECT count() FROM table WHERE ...;

观察 processor 链名称。不粘贴未执行输出。


十、学术谱系:Volcano → MonetDB/X100 → Processors

阶段 文献 / 系统 数据单元 要点
1994 Graefe, Volcano 一行 / next() 可扩展迭代器;虚调用与分支多
2005 Boncz et al., MonetDB/X100, CIDR 向量批 cache-conscious;打满流水线与 SIMD
2018 Kersten et al., Compiled and Vectorized Queries, VLDB 编译算子 vs 解释向量 无绝对赢家:查询形状、编译摊销、缓存行为决定
2010s+ ClickHouse IProcessor / Block 数千~数万行 Block 默认向量化;可选 compile_expressions JIT

谱系结论:第 1 篇已钉 C-Store 存储侧;本篇钉执行侧——CH 主路径是 X100 式向量解释,不是 HyPer 式全查询 codegen。compile_expressions 是局部加速,不改变 Pipeline 以 Block 为边界的模型。

10.1 争论:Compiled vs Vectorized

立场 代表 主张
向量解释优先 X100 / VectorWise 传统;CH 默认 批处理已够满流水线;无编译延迟;易调试
编译优先 HyPer 等 去掉解释循环,紧循环 + 特化类型
实证调和 Kersten et al., VLDB 2018 两者在不同算子/硬件上互有胜负;混合常见

工程上:CH 用向量 Block 保可观测与多租户公平;JIT 仅覆盖热点表达式——与「全计划 LLVM」不是同一设计点。

10.2 工程间隙

论文设定 ClickHouse 24.x
单查询独占机器 多查询共享 max_threads、内存 tracker
TPC-H 长 scan 短交互查询 + 持续 merge 抢 CPU
理想列向量对齐 Nullable / LowCardinality / 字符串偏移使 autovec 不总触发
少谈存储读 MergeTreeSource 解压 granule 常成瓶颈(第 5 篇)

10.3 开放问题

  1. CH 何时值得默认打开更激进的 codegen? 可检验:同查询开关 compile_expressions 的 CPU 与首次延迟(入口:Kersten VLDB’18;CH settings 文档)。
  2. Block 大小是否应随算子自适应? 固定 max_block_size 对 filter 选择性极端时可能浪费;社区有讨论,无统一论文结论。
  3. 与 DuckDB morsel 的并行模型谁更适合多核 skew? 见第 12 篇。

十一、小结

列存执行核心:Block 列向量 + Processor DAG + 批量算子。学术坐标:Volcano → X100 →(Kersten 争论)→ CH Processors。读路径产出 Block,算子链在 Block 上向量化,直到输出客户端。


上一篇压缩与编码

下一篇查询读取路径


参考资料

核心论文

  1. Graefe, Volcano—An Extensible and Parallel Query Evaluation System, IEEE TKDE 1994(A 级)。
  2. Boncz et al., MonetDB/X100: Hyper-Pipelining Query Execution, CIDR 2005(A 级)。
  3. Kersten et al., Everything You Always Wanted to Know About Compiled and Vectorized Queries But Were Afraid to Ask, PVLDB 2018(争论;A 级)。

规范 / 源码 / 文档

  1. ClickHouse Documentation, Architecture Overview(Processors / Block;A 级)。
  2. ClickHouse Source, v24.3, src/Processors/src/Columns/src/Core/Block.h(A 级)。
  3. PostgreSQL 系列, 执行器(Volcano 对照)。

Block 与 Chunk

BlockCore/Block.h)含多列;Pipeline 中 Chunk 携带 Block 或列子集 + 行数。max_block_size 控制单行算子输出规模。

IProcessor 状态机

prepare() 返回 NeedData / Ready / Finishedwork() 消费输入 Chunk、产出输出 Chunk。PipelineExecutor 多线程调度 ready 节点,避免全局锁(官方 Architecture Processors)。

与 PG 执行器对照

PG ClickHouse
ExecProcNode 拉一行 IProcessor::work 拉一批
TupleTableSlot Block / ColumnVector
ExprState EEO ExpressionActions 列循环
nodeHashjoin.c 逐行 probe HashJoin transform 批量

SIMD

Columns/Common/Simd* 与函数实现(如 FunctionsArithmetic)对固定宽度类型使用 intrinsics;具体是否触发取决于类型与编译标志(-march)。

读完这篇,下一步读什么

优先读同系列或同问题的下一篇,把单篇消费变成主题集群。

2026-06-18 · database / storage

【列存引擎内核】列存基础与 ClickHouse 架构

行存 vs 列存的带宽、压缩与向量化三角;ClickHouse Server 进程模型、线程池与 MergeTree 引擎家族地图;src/Storages 与 src/Processors 源码入口。对照 PG 行存与 LSM 写优化路径,版本锚定 ClickHouse 24.x LTS。

2026-06-18 · database / storage

【列存引擎内核】MergeTree Part 文件格式

ClickHouse MergeTree Part 目录结构:columns.txt、checksums.txt、.bin、.mrk2、primary.idx 语义,Granule 与 Mark 的定位作用,Wide/Compact 布局与 MergeTreeDataPart 源码入口。版本锚定 24.x LTS。

2026-06-18 · database / storage

【列存引擎内核】压缩与编码

ClickHouse 列压缩:LZ4、ZSTD、Delta、DoubleDelta、Gorilla 时序编码与列类型关系;CODEC 链顺序、LowCardinality 与 PG TOAST 对照。压缩比须本机实测,本文不编造倍数。

2026-06-18 · database / storage

【列存引擎内核】查询读取路径

MergeTree SELECT 读路径:Mark Range 定位 Granule、PREWHERE 与 WHERE、Part 级并行与 max_threads。EXPLAIN indexes=1 解读方法。24.x LTS,无伪造 EXPLAIN 输出。


By .