读者在 lakehouse 第 18 章 已经看到:Trino 读 Iceberg 表时,partition predicate 可以在 manifest 层裁掉大量文件。那条链路回答的是 引擎如何把读表范围缩小到必要的 Parquet 文件。但同一套湖仓 SQL 里还有另一组问题:一条带多表 join 的 SELECT 在 Coordinator 上怎么变成 Stage、Worker 之间为什么要 shuffle、CBO 估错行数后 join 顺序怎么把集群打满——lakehouse/18 讲下推漏斗,不讲引擎内部的 IR、优化与 MPP 执行。
本文是本系列 第 1 篇,不教 Trino 安装,而是建立三个贯穿全系列 18 篇的心智模型:
- 分布式 OLAP 查询引擎 = SQL 前端 + 逻辑/物理优化 + 执行模型 + MPP 调度 + Connector 下推。
- 嵌入式与分布式 的分界不在「能不能读 Parquet」,而在 数据量、并发、跨源联邦、shuffle 网络代价 是否迫使引入 Coordinator/Worker。
- 批式扫描与交互式查询 共享列存与向量化直觉(columnar-engine 系列),但延迟目标、资源隔离与失败重试语义不同(stream-processing 第 1 篇 的流批边界)。
后文默认读者具备 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 可在单进程内做 向量化 + 多线程 pipeline(columnar-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/18 的 layout 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
文档结构上的对照。
参考资料
- Trino Documentation, Overview / SQL(架构与 SQL 执行路径)。
- Apache Spark Documentation, Spark SQL Guide(3.5+)。
- DuckDB Documentation, Architecture / SQL(1.5.x)。
- lakehouse 第 18 章(读湖下推漏斗)。
- stream-processing 第 1 篇(流批边界)。
- columnar-engine 第 4 篇(向量化执行)。
- 本系列 index(18 篇依赖与阅读路径)。
返回 系列目录 | 下一篇:SQL 解析、分析与逻辑计划
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【分布式 OLAP 查询引擎】引擎选型与数据平台阅读地图
用决策树收束 Trino/Spark/ClickHouse/DuckDB/DataFusion/PostgreSQL 的适用边界:交互式联邦、批 ETL、嵌入式分析、流批一体各走哪条路径;给出能力对照表(无吞吐排名)与 postgresql→columnar→lakehouse→stream→query-engine 全栈阅读顺序,闭合数据平台栈。
【分布式 OLAP 查询引擎】Trino · Spark · DuckDB · 优化与 MPP 执行
闭合数据平台栈最后一块:从 SQL 解析与 Calcite 式优化,到 Volcano/向量化执行、Trino Coordinator/Worker 与 shuffle,再到 Iceberg connector 下推与生产排查。承接 lakehouse 第 18 章读湖视角,补全「谁在做 planning」的引擎内核层。
【分布式 OLAP 查询引擎】Coordinator 与 Worker:Query / Stage / Task / Driver
拆解 Trino Coordinator 与 Worker 的职责边界,从 Query 到 Stage、Task、Driver、Operator 的五层执行模型,Split 调度与 data locality,并与 Spark Driver/Executor/Stage 对照。
【分布式 OLAP 查询引擎】DuckDB 与 DataFusion:嵌入式分析对照
从单进程向量化 pipeline 与 morsel-driven 并行出发,对照 DuckDB 1.5.4 与 Apache DataFusion 的 planner/executor 边界;说明何时选嵌入式读湖、何时必须上 Trino MPP;与 columnar-engine DuckDB 存储篇分工,并用本机实测 EXPLAIN 与 Parquet 投影下推数据锚定结论。