怎么理解ClickHouse的向量化执行

这是一个理解 ClickHouse 性能本质的核心问题。如果只用一句话概括:

ClickHouse 的向量化执行,本质是:
不是"一行一行算",而是"一批一批算"。

下面我分 直觉 → 内部机制 → 和行式执行对比 → 为什么快 → 常见误解 五个层次给你讲清楚。


一、先用直觉理解(非常重要)

❌ 传统行式执行(Row-at-a-time)

text 复制代码
for each row:
    取一行
    计算表达式
    判断条件
    输出
  • 每行一次函数调用
  • 分支判断频繁
  • CPU cache 利用率低

✅ ClickHouse 向量化执行(Vectorized)

text 复制代码
for each block (1024 ~ 8192 rows):
    取一整列(数组)
    在数组上做计算
    一次性输出结果列
  • 一次处理一批数据
  • 函数作用于数组(vector)
  • 大量减少 CPU 指令 & 分支

👉 这是 ClickHouse 快的根本原因之一


二、ClickHouse 内部是怎么做的

1️⃣ Block(数据块)

ClickHouse 的最小执行单元不是 row,而是 Block

  • 一个 Block ≈ 一批行
  • 每一列是一个数组(Column
  • 默认 block size:max_block_size(通常 8192)

示意:

text 复制代码
Block:
  user_id   → [u1, u2, u3, ...]
  price     → [10, 20, 30, ...]
  cnt       → [1, 2, 3, ...]

2️⃣ Expression 在列上执行

sql 复制代码
SELECT price * cnt
FROM t
WHERE price > 10

执行逻辑:

  • price > 10

    → 对 price 列数组一次性比较

    → 生成 Bool mask

  • price * cnt

    → 两个数组做逐元素乘法

👉 没有"单行循环"


三、和行式执行的对比(关键)

维度 行式执行 CK 向量化
处理单位 Block(批)
函数调用 每行一次 每列一次
CPU 分支 极少
Cache 命中
SIMD 几乎不可用 可大量使用

四、为什么向量化执行这么快

1️⃣ CPU Cache 友好

  • 连续内存访问
  • 顺序扫描
  • 几乎没有 random access

2️⃣ SIMD 自动加速

现代 CPU 可以:

  • 一条指令处理多个值(AVX2 / AVX-512)

例如:

text 复制代码
price > 10

→ 一条指令比较 8~16 个值


3️⃣ 函数调用 / 分支极少

  • 行式:一行一个 if
  • 向量化:一次判断一整列

五、向量化 ≠ 列存(容易混淆)

概念 含义
列存 数据存储方式
向量化执行 数据处理方式
  • 列存 ≠ 必然向量化
  • 行存 ≠ 不能向量化(但很难)

👉 ClickHouse 是:

列存 + 向量化执行 + 顺序扫描

三者叠加,才有极致性能。


六、ClickHouse 中"哪些地方用到了向量化"

几乎全部核心算子:

  • WHERE 过滤
  • 表达式计算
  • GROUP BY
  • 聚合函数
  • 排序(部分阶段)
  • JOIN(build/probe 阶段)

七、什么时候向量化会"失效"

⚠️ 以下场景会降低向量化优势:

1️⃣ 复杂 UDF / lambda

2️⃣ 每行逻辑分支非常复杂

3️⃣ 极端小数据量(几十行)

4️⃣ 大量 LIKE '%xxx%' / 正则

👉 这时 CPU 成本会上来,但仍比行式好。


八、一个非常重要的工程认知

ClickHouse 的性能不是"索引查得快",
而是"即使扫,也扫得极快"。

向量化执行让"全表扫描"变成了一个可接受、甚至高效的操作。


九、一句话总结(面试级)

ClickHouse 的向量化执行是:
以 Block 为单位,把列当数组,用 SIMD 和顺序内存访问对整批数据做计算,从而极大降低 CPU 指令数和 cache miss。


一、典型场景

  • Flink 实时写入 CK(明细 / 底池 / 选品结果)

  • CK 上:

    • 圈品(等值 + 模糊条件)
    • 统计分析(group by、count、sum)
    • 偶尔 LIKEIN、范围过滤
  • 数据量:百万~十亿级

  • 很关心:

    • 为啥没索引也能跑
    • 为啥 LIKE 不一定慢
    • 为啥扫全表还能接受

👉 这些 全部依赖向量化执行


二、什么 SQL「最能吃满」向量化(你应该多写)

✅ 1️⃣ 等值 / IN / 范围过滤(无索引也不怕)

sql 复制代码
SELECT count(*)
FROM sku_pool
WHERE pool_type = 3
  AND status = 1
  AND price BETWEEN 100 AND 300;

为什么快?

  • pool_type = 3 → 对一整列做批量比较
  • status = 1 → 布尔 mask
  • 没有逐行 if
  • 扫得快 + 算得快

👉 这是 CK 最擅长的形态


✅ 2️⃣ 统计(典型 OLAP)

sql 复制代码
SELECT
    category_id,
    countDistinct(sku_id)
FROM sku_event
WHERE event_date = '2026-01-12'
GROUP BY category_id;

向量化体现在哪?

  • countDistinct 在 block 上批量处理
  • GROUP BY 用哈希表 + 批量 probe
  • cache 命中率极高

👉 这是 CK 的绝对舒适区


✅ 3️⃣ 模糊过滤里的"可控模糊"

sql 复制代码
WHERE title LIKE '耐克%'

比你想象中快的原因:

  • 扫描是列式顺序 IO
  • 前缀匹配在 vector 上跑
  • 比 MySQL 一行一行判断快得多

⚠️ 但注意:
LIKE '%耐克%' 就开始吃 CPU 了(后面说)


三、哪些 SQL 会"拖垮"向量化(你要警惕)

❌ 1️⃣ 大字段 + %LIKE%

sql 复制代码
WHERE json_str LIKE '%"brand":"NIKE"%'

问题在哪?

  • 每行都要做子串扫描
  • 字符串很长
  • SIMD 优势基本丢失

👉 不是 I/O 慢,是 CPU 被吃光


❌ 2️⃣ 复杂 UDF / Lambda

sql 复制代码
WHERE my_custom_func(col1, col2) = 1
  • 每个 block 都要走复杂逻辑
  • 很难 vectorize
  • 退化成"伪行式"

❌ 3️⃣ 极小结果集 + 频繁点查

sql 复制代码
SELECT *
FROM t
WHERE id = 'xxx'
LIMIT 1;
  • CK 能做
  • 但这不是它的强项
  • QPS 高时不如行存数据库

👉 向量化是"批处理友好",不是"点查友好"


四、把「向量化」用在圈品里的正确姿势(很关键)

❌ 错误姿势(行式思维)

"我要一条条 SKU 判断是否符合条件"

✅ 正确姿势(向量化思维)

"我要让每个条件都能在整列上一次性判断"

例如:

sql 复制代码
SELECT sku_id
FROM sku_pool
WHERE
    category_id IN (101,102,103)
    AND price BETWEEN 80 AND 150
    AND brand IN ('NIKE','ADIDAS')
    AND score > 60;
  • 每个条件 → 一次列级判断
  • 最终 mask 合并
  • 输出命中行

👉 这是 CK 天生擅长的圈品方式


五、为什么你会感觉「没索引也不慢」

可以用一句话解释:

CK 的优势不在"跳过多少数据",而在"即使全扫,也用向量化把 CPU 成本压到极低"


六、把这套理解映射回你之前的问题

1️⃣ 为啥 CK 不强调行存?

→ 行存会破坏向量化执行

2️⃣ 为啥 LIKE 和 = 没索引时差别没你想象大?

→ 都在扫,差在 CPU 指令数量

3️⃣ 为啥 CK 适合圈品、分析、不适合 OLTP?

→ 向量化 = 批处理友好


七、一个"工程级"的总结(你可以直接在设计里用)

ClickHouse 的 SQL 设计目标,不是"少扫数据",
而是"让每一次扫描都尽可能线性、连续、向量化"。

当你写 SQL 时,应该问自己一句:

这个条件,是不是能在"列级别"一次性算完?

如果答案是 ,那这条 SQL 基本就稳了。


相关推荐
侠客行03173 小时前
Mybatis连接池实现及池化模式
java·mybatis·源码阅读
蛇皮划水怪3 小时前
深入浅出LangChain4J
java·langchain·llm
较劲男子汉5 小时前
CANN Runtime零拷贝传输技术源码实战 彻底打通Host与Device的数据传输壁垒
运维·服务器·数据库·cann
老毛肚5 小时前
MyBatis体系结构与工作原理 上篇
java·mybatis
wypywyp5 小时前
8. ubuntu 虚拟机 linux 服务器 TCP/IP 概念辨析
linux·服务器·ubuntu
风流倜傥唐伯虎5 小时前
Spring Boot Jar包生产级启停脚本
java·运维·spring boot
Doro再努力5 小时前
【Linux操作系统10】Makefile深度解析:从依赖推导到有效编译
android·linux·运维·服务器·编辑器·vim
senijusene5 小时前
Linux软件编程:IO编程,标准IO(1)
linux·运维·服务器
不像程序员的程序媛5 小时前
Nginx日志切分
服务器·前端·nginx
Yvonne爱编码5 小时前
JAVA数据结构 DAY6-栈和队列
java·开发语言·数据结构·python