TL;DR

DuckDB 是一个嵌入式 OLAP 数据库,融合了列存储的 PAX 布局与向量化(Vectorized)执行引擎,通过 Morsel-Driven 并行实现高效分析查询。

三层设计

┌─────────────────────────────────────┐
│         Morsel-Driven 并行          │
│  ┌─────────┐ ┌─────────┐           │
│  │ Thread 1│ │ Thread 2│ ...       │
│  └────┬────┘ └────┬────┘           │
│       │           │                 │
│  ┌────▼───────────▼────┐           │
│  │  向量化执行引擎       │           │
│  │  (Vector Size = 2048)│           │
│  └──────────┬──────────┘           │
│             │                       │
│  ┌──────────▼──────────┐           │
│  │  PAX 列式存储布局     │           │
│  └─────────────────────┘           │
└─────────────────────────────────────┘

PAX(Partition Attributes Across)布局

DuckDB 不采用纯列存(DSM),而是 PAX:每个 Row Group 内部按列组织:

Row Group (122,880 rows)
┌──────────────────────────────────────┐
│ Column Chunk 1 (trip_id):            │
│ [val1, val2, ..., val122880]         │
├──────────────────────────────────────┤
│ Column Chunk 2 (timestamp):          │
│ [ts1, ts2, ..., ts122880]            │
├──────────────────────────────────────┤
│ Column Chunk 3 (amount):             │
│ [amt1, amt2, ..., amt122880]         │
└──────────────────────────────────────┘

为什么是 PAX 而不是纯列存?

  • 纯列存(DSM):按列分文件,不同列在不同文件 → 多列查询需多次 IO
  • 行存(NSM):按行存 → scan 时拖入不需要的列
  • PAX:折中方案,每 Row Group 内列连续存储 → 单次 IO 可读多列

向量化执行

DuckDB 的向量化执行引擎每次处理 2048 行STANDARD_VECTOR_SIZE),而非逐行处理:

逐行执行(Volcano):
  for row in table:
    col_a = row.a        ← 函数调用 × N
    col_b = row.b
    result = col_a + col_b

向量化执行(DuckDB):
  vector_a = table.a[0:2048]     ← 一次函数调用
  vector_b = table.b[0:2048]
  result = vector_add(vector_a, vector_b)  ← SIMD 加速

优势:

  1. 减少虚函数调用(2048 行一次 vs 每行一次)
  2. CPU cache 友好(批量数据在 L1/L2 中)
  3. 可利用 SIMD 指令(SSE/AVX)批量计算

Morsel-Driven 并行

// 查询执行时,数据被切分为 Morsels
// 每个 Morsel 约包含几千行,由工作线程动态分配

while (true) {
    auto morsel = pipeline->GetNextMorsel();
    if (!morsel) break;  // 没有更多数据
    ExecuteOperator(morsel);  // 在当前线程执行
}

这种模式相比分区域并行(每个线程固定分一块数据)更灵活,能自动处理数据倾斜。

性能特征

场景 DuckDB 优势
全表扫描 列式扫描,跳过无关列
聚合计算 SIMD 加速,向量批量聚合
Join Morsel-Parallel Hash Join
单机分析 零配置,进程内嵌入

总结

DuckDB 通过 PAX 列式存储 + 向量化执行 + Morsel 并行的三层设计,在嵌入式场景中实现了接近大型 OLAP 系统的分析性能。对于数据分析和 ETL 场景,它是 SQLite 在 OLTP 地位的 OLAP 对应物。

参考