土法炼钢兴趣小组的算法知识备份

【分布式 OLAP 查询引擎】OLAP 查询引擎全景:从单进程到 MPP

文章导航

分类入口
databasedistributed
标签入口
#olap#trino#spark#duckdb#mpp#query-engine#lakehouse#htap#interactive-analytics#cbo

目录

读者在 lakehouse 第 18 章 已经看到:Trino 读 Iceberg 表时,partition predicate 可以在 manifest 层裁掉大量文件。那条链路回答的是 引擎如何把读表范围缩小到必要的 Parquet 文件。但同一套湖仓 SQL 里还有另一组问题:一条带多表 join 的 SELECT 在 Coordinator 上怎么变成 Stage、Worker 之间为什么要 shuffle、CBO 估错行数后 join 顺序怎么把集群打满——lakehouse/18 讲下推漏斗,不讲引擎内部的 IR、优化与 MPP 执行。

本文是本系列 第 1 篇,不教 Trino 安装,而是建立三个贯穿全系列 18 篇的心智模型:

后文默认读者具备 SQL 与基本分布式概念,但不假设读过 Calcite 源码或调过 Trino resource group。

环境说明:本机为 WSL2(Linux 6.6.87.2)、i9-12900K / 32 GiB,未部署 Docker Compose Trino/Spark 栈(无 JVM 查询集群)。架构与机制结论来自 Trino 476+、Spark 3.5+、DuckDB 1.5.x 官方文档;Trino/Spark 的 EXPLAIN 片段不在此篇粘贴未实测输出。DuckDB 本机实验见 第 2 篇reproduce/run_duckdb_experiments.py


一、OLTP、OLAP 与 HTAP:优化目标不同

维度 OLTP(行存) OLAP(列存/湖) HTAP(混合,本系列不展开)
典型负载 点查、短事务、高并发写 大表扫描、复杂 join、聚合 同一集群兼顾两者
存储 B-Tree / LSM 行页 列块、Parquet、MergeTree Part 双引擎或统一格式
优化器 低延迟路径、索引 CBO、join reorder、下推 路由或副本分离
执行 进程内 volcano、短 pipeline 向量化 batch、MPP shuffle 资源隔离是核心难题
系列落点 postgresql-kernel 本系列 + columnar-engine db-frontier 可选

postgresql-kernel 的 B-Tree + MVCC 优化 单行与短范围;OLAP 引擎优化 少次 I/O 读大量列、在内存/network 预算内完成 join/agg。把 PG 的「索引选错」直觉(PG 第 10 篇)迁移到 Trino 时,对应问题往往是 统计过期导致 broadcast 误判Iceberg 分区谓词未下推第 15 篇)。

1.1 延迟口径:交互式 OLAP 指什么

Trino 文档把产品定位在 interactive analytics:秒级到分钟级 ad-hoc SQL,而非 MapReduce 小时级批 job。口径上区分:

类型 输入边界 失败语义 典型引擎
批式 ETL 分区/目录固定 重跑 stage Spark batch
交互式 SQL 用户提交即规划 单查询 cancel/retry Trino、ClickHouse
流式增量 无界 log checkpoint Flink(stream-processing

本系列 以交互式分布式 OLAP(Trino 主线) 为锚;Spark SQL 作批/湖仓与 AQE 对照(第 13 篇);流式窗口与 state 不重复stream-processing 第 1 篇)。


二、嵌入式 vs 分布式:何时需要 MPP shuffle

flowchart TB
  subgraph embed ["Embedded OLAP"]
    APP["App / Notebook"]
    DDB["DuckDB / DataFusion"]
    FILES["Local Parquet / Iceberg files"]
    APP --> DDB --> FILES
  end
  subgraph mpp ["Distributed MPP"]
    CLI["JDBC / CLI"]
    COORD["Coordinator<br/>plan + schedule"]
    W1["Worker"]
    W2["Worker"]
    S3["Object storage / Hive metastore"]
    CLI --> COORD
    COORD --> W1
    COORD --> W2
    W1 --> S3
    W2 --> S3
  end
信号 倾向嵌入式(DuckDB) 倾向分布式(Trino/Spark)
数据规模 单机内存 + 磁盘可承受 单表 TB 级、需并行 scan
并发 少量会话、嵌入进程 多租户、队列与资源组
数据源 本地/挂载文件、单 catalog 多 catalog 联邦、Remote IR
Join 中间结果 本地 hash table 够装 partitioned shuffle
运维 无 server 进程 Coordinator HA、Worker 扩缩

DuckDB 可在单进程内做 向量化 + 多线程 pipelinecolumnar-engine DuckDB 篇);一旦 fact 表分布在对象存储、join 维表需跨节点 repartition,就必须引入 Exchange第 11 篇)。选型不在此篇做排名,第 18 篇 给决策树。


三、一条 SELECT 的分层:IR 地图预览

Trino 查询路径(来源:Trino Documentation,Overview / SQL)可粗分为:

flowchart LR
  SQL["SQL text"] --> PARSE["Parser → AST"]
  PARSE --> ANALYZE["Analyzer<br/>types, names"]
  ANALYZE --> LOG["Logical plan"]
  LOG --> OPT["Optimizer<br/>rules + CBO"]
  OPT --> PHYS["Physical plan<br/>operators"]
  PHYS --> DIST["Distributed plan<br/>stages, exchange"]
  DIST --> TASK["Tasks on Workers"]
阶段 输入 输出 本系列篇章
Parse / Analyze 字符串 带类型的关系代数树 第 2 篇
Logical optimize 逻辑算子 谓词下推、列裁剪后的逻辑树 第 3 篇
Physical + CBO 统计信息 HashJoin vs MergeJoin、join order 第 4–5 篇
Distributed Split 元数据 Stage 边界、Remote Exchange 第 10–12 篇
Execute Page 流 结果集 第 6–9 篇

lakehouse/18layout constraint(分区/文件/row-group)在 Trino 中由 Iceberg connector + planner 在 logical/physical 边界注入(第 15 篇);本系列从 谁发起 constraint 补全 lakehouse 未展开的内核层。


四、执行模型三角:Volcano、向量化、morsel-driven

三种执行语义在本系列 第 6–7 篇 展开;此处只定坐标:

模型 数据单位 驱动方式 代表
Volcano 一行 Tuple 父算子 next() pull 经典 PG、早期 Presto 部分算子
Vectorized batch 列向量 \(N\) 算子间传递 Arrow/Page DuckDB、ClickHouse、Trino 多数算子
Morsel-driven 列向量 + 动态切分 work-stealing 并行 scan DuckDB、Hyper 系

columnar-engine 第 4 篇 从 ClickHouse Block/IProcessor 拆解 batch 执行;本系列 第 7 篇 对照 Trino Page 与 DuckDB pipeline。列存文件格式lakehouse/02 Parquet)与 执行 batch 是衔接关系:读路径产出向量,算子链在向量上算。


五、数据平台栈闭合图

flowchart TB
  PG["postgresql-kernel<br/>行存 OLTP"]
  COL["columnar-engine<br/>MergeTree / 向量化"]
  LAKE["lakehouse<br/>Iceberg + Parquet"]
  STREAM["stream-processing<br/>Flink 入湖"]
  QE["query-engine<br/>本系列"]
  PG --> COL
  COL --> LAKE
  LAKE --> STREAM
  LAKE --> QE
  STREAM -.->|CDC / 入湖| LAKE
已覆盖系列 本系列补什么
写入路径 PG/InnoDB、Flink sink 不写
文件与表格式 lakehouse 不重复 Parquet 编码
读与算 lakehouse/18 下推漏斗 SQL → plan → MPP → connector 下推发起
实时 stream-processing 交互式 vs 流式延迟(第 1 篇

Lakehouse 公式 Lakehouse = 列式文件 + 对象存储 + 表格式 + catalog + 查询引擎 中,前五项已有系统文章;查询引擎 独立成系列,避免把 Trino 当成「扫 Iceberg 的黑盒」。


六、引擎对照:Trino 主线与 Spark / DuckDB

维度 Trino 476+ Spark 3.5+ DuckDB 1.5.x
进程模型 Coordinator + Worker Driver + Executor 嵌入宿主进程
Planner 自研(Calcite 借鉴) Catalyst 内置
分布式 shuffle Exchange ShuffleDependency 无(本地 parallel)
湖格式 Iceberg connector 成熟 Iceberg/Delta 一等 Iceberg extension
可观测 EXPLAIN ANALYZE Spark UI / explain EXPLAIN ANALYZE

Presto/Trino 分叉:2019 年 Presto 商标与 governance 分裂,Trino 为 trinodb/trino 延续(B 级历史事实,一句带过)。本系列代码与行为以 Trino 为准。


七、全系列 18 篇地图

flowchart TB
  subgraph base ["基础 1–3"]
    A1["01 全景"]
    A2["02 逻辑计划"]
    A3["03 Calcite/规则"]
  end
  subgraph cbo ["CBO 4–5"]
    B4["04 统计代价"]
    B5["05 Join 规划"]
  end
  subgraph exec ["执行 6–9"]
    C6["06 Volcano"]
    C7["07 向量化"]
    C8["08 Scan"]
    C9["09 HashJoin/Agg"]
  end
  subgraph mpp ["MPP 10–12"]
    D10["10 Coordinator"]
    D11["11 Shuffle"]
    D12["12 Trino 全路径"]
  end
  subgraph eng ["引擎 13–15"]
    E13["13 Spark"]
    E14["14 DuckDB"]
    E15["15 Iceberg 下推"]
  end
  subgraph prod ["生产 16–18"]
    F16["16 内存 Spill"]
    F17["17 故障排查"]
    F18["18 选型地图"]
  end
  A1 --> A2 --> A3 --> B4 --> B5
  A1 --> C6 --> C7 --> C8 --> C9
  A1 --> D10 --> D11
  B5 --> D12
  C8 --> D12
  D10 --> D12
  D12 --> E13 --> E14 --> E15
  C9 --> F16
  D11 --> F16
  D12 --> F16 --> F17 --> F18

7.1 阅读路径

读者背景 建议路径
数据平台全栈 1 → 2 → 4 → 10 → 12 → 15 → 18
从 lakehouse/18 来 2 → 3 → 5 → 12 → 15
从 columnar-engine 来 1 → 6 → 7 → 14
Trino 运维 1 → 10 → 12 → 16 → 17
优化器理论 2 → 3 → 4 → 5 → 6

八、与 stream-processing 的边界

stream-processing 系列 解决 无界 log + 有状态计算 + EOS 入湖;本系列解决 有界表上的 declarative SQL + CBO + MPP。交叉点:

话题 stream-processing 本系列
窗口聚合 Flink state + watermark SQL 窗口函数(不单独成篇)
入湖 Committer / snapshot Trino 读已提交 snapshot
背压 算子 chain 反压 查询内存账户、spill(第 16 篇
延迟 毫秒–秒 秒–分钟(交互式)

Flink SQL 与 Trino SQL 语法相似但运行时完全不同;勿用流作业 mental model 直接推断 Trino 的 stage 并行度。


九、本系列边界

不展开 原因
SQL 语法大全、BI 工具 机制篇优先
云 Athena/BQ 内部实现 与开源内核无关
ClickHouse 存储层全文 columnar-engine
GPU 查询加速 db-frontier 边界

承诺展开:IR 层级、CBO 与统计、三种执行模型、Trino MPP、EXPLAIN ANALYZE 判读、Iceberg planner 下推(对读 lakehouse/18)。


十、本地实验入口

DuckDB(本机可跑)post/db/query-engine/reproduce/run_duckdb_experiments.py 生成 10 万行 orders、5000 行 customer,输出 EXPLAIN 与 3 次 EXPLAIN ANALYZE 中位数(见 第 2 篇)。

Trino + Iceberg(需 Docker)reproduce/docker-compose.yml 扩展 lakehouse reproduce;未在本写作环境启动时不粘贴 Trino plan 片段。


十一、小结

OLAP 查询引擎的核心不是「把 PG 放大到集群」,而是 在列存/湖文件上,用 CBO 选 join 与 scan 路径,用 MPP shuffle 扩展单机算力,用 connector 把谓词推到 layout 层。嵌入式 DuckDB 与分布式 Trino 共享 逻辑计划与向量化 直觉,差在 Exchange 与资源隔离

下一篇进入 Parser、Analyzer 与 LogicalPlan:同一条 SQL 在 DuckDB EXPLAIN 与 Trino logical plan 文档结构上的对照。


参考资料

  1. Trino Documentation, Overview / SQL(架构与 SQL 执行路径)。
  2. Apache Spark Documentation, Spark SQL Guide(3.5+)。
  3. DuckDB Documentation, Architecture / SQL(1.5.x)。
  4. lakehouse 第 18 章(读湖下推漏斗)。
  5. stream-processing 第 1 篇(流批边界)。
  6. columnar-engine 第 4 篇(向量化执行)。
  7. 本系列 index(18 篇依赖与阅读路径)。

返回 系列目录 | 下一篇:SQL 解析、分析与逻辑计划

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-07-07 · database / distributed

【分布式 OLAP 查询引擎】引擎选型与数据平台阅读地图

用决策树收束 Trino/Spark/ClickHouse/DuckDB/DataFusion/PostgreSQL 的适用边界:交互式联邦、批 ETL、嵌入式分析、流批一体各走哪条路径;给出能力对照表(无吞吐排名)与 postgresql→columnar→lakehouse→stream→query-engine 全栈阅读顺序,闭合数据平台栈。

2026-07-07 · database / distributed

【分布式 OLAP 查询引擎】Trino · Spark · DuckDB · 优化与 MPP 执行

闭合数据平台栈最后一块:从 SQL 解析与 Calcite 式优化,到 Volcano/向量化执行、Trino Coordinator/Worker 与 shuffle,再到 Iceberg connector 下推与生产排查。承接 lakehouse 第 18 章读湖视角,补全「谁在做 planning」的引擎内核层。

2026-07-07 · database / distributed

【分布式 OLAP 查询引擎】DuckDB 与 DataFusion:嵌入式分析对照

从单进程向量化 pipeline 与 morsel-driven 并行出发,对照 DuckDB 1.5.4 与 Apache DataFusion 的 planner/executor 边界;说明何时选嵌入式读湖、何时必须上 Trino MPP;与 columnar-engine DuckDB 存储篇分工,并用本机实测 EXPLAIN 与 Parquet 投影下推数据锚定结论。


By .