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

【分布式 OLAP 查询引擎】Scan、Filter 与 Project:Split 与下推边界

文章导航

分类入口
databasedistributed
标签入口
#table-scan#connector-split#predicate-pushdown#column-pruning#trino-spi#filter#project#iceberg

目录

优化器把逻辑计划变成物理计划后,执行往往从 TableScan 开始。lakehouse 第 18 章读湖漏斗 讲了 partition/file/row-group 裁剪;本篇从 Trino 476+ 执行与 SPI 回答:Coordinator 如何把 Scan 切成 Split、connector 如何只读必要 、哪些 Filter/Project 必须留在引擎里。


一、TableScan 在 pipeline 中的位置

Trino worker 上,TableScanOperator(A 级:TableScanOperator.java)是 SourceOperator:只实现 getOutput(),通过 ConnectorPageSourceProvider.createPageSource(...)Page第 6 篇)。

flowchart TB
  COORD["Coordinator<br/>schedule splits"]
  TS["TableScanOperator"]
  CPS["ConnectorPageSource"]
  STO["Object store / DB"]
  COORD -->|"Split assignment"| TS
  TS --> CPS
  CPS --> STO
  TS --> FIL["FilterOperator"]
  FIL --> PRJ["ProjectOperator"]
组件 职责
ConnectorSplitManager 把表切成可并行处理的 Split
ConnectorPageSourceProvider 给定 split + 列列表,产生 Page
ConnectorMetadata planning 阶段接受 下推(filter / project / limit / topN)

Scan 本身不做 SQL 表达式求值;表达式在 FilterOperator / ProjectOperator 或已下推到 connector 的 handle 里完成。


二、ConnectorSplit:并行与 locality

ConnectorSplit(SPI)是 worker 上并行度的基本单位ConnectorSplitManager.getSplits(...) 返回一批 split,Coordinator 调度到 Task(Trino Documentation ConnectorsConnectorSplitManager)。

2.1 Split 粒度因 connector 而异

数据源 Split 典型含义 Locality
Hive / Iceberg 一个或一组数据文件 getAddresses() 提示对象存储前缀 / 缓存节点
JDBC 按分区或 LIMIT 切分 常无 affinity
TPCH connector 合成 split 测试用
单机内存 整表或行范围 N/A

Split 越小,并行度越高,但 scheduling 与元数据开销越大;Iceberg 常在 file 级切 split,并依赖 manifest 已裁掉的文件列表(第 15 篇)。

2.2 Dynamic Filter 与 Scan

TableScanOperator 构造 PageSource 时可传入 DynamicFilter(runtime filter):build 侧 join 运行中产生的 bloom/min-max 谓词,缩小 probe 端 scan(与 第 5 篇 DPP 衔接)。这是 执行期 对 Split 内数据的二次过滤,不改变 Split 个数。

sequenceDiagram
  participant HB as Hash Build side
  participant DF as DynamicFilter
  participant TS as TableScan
  HB->>DF: publish domain
  TS->>DF: getCurrentPredicate()
  TS->>TS: skip rows / pages in split

三、Column Pruning(Projection Pushdown)

Projection pushdown:优化器从 SELECT、join key、谓词列收集 必要列,经 ConnectorPageSourceProvider.createPageSource(..., List<ColumnHandle> columns, ...) 传给 connector(Trino Documentation PushdownProjection pushdown)。

阶段 谁决定列集 效果
Analyzer 解析 SELECT * 展开 逻辑列依赖
Optimizer 裁剪未引用列 更新 TableScanNode 列列表
Connector 只读文件内对应列 减少 IO / 解压

Parquet / ORC 上 pruning 在 文件列 chunk 级生效;列存与行存 JDBC 源的能力差异极大,需查各 connector 文档。

验证EXPLAINTableScancolumns 列表应只剩必要列;Iceberg 场景还可对照 lakehouse/18 的 scanned bytes。


四、谓词与 Limit 下推

Trino 在 planning 时反复调用 ConnectorMetadata(A 级:Trino Documentation Connectors):

方法 下推内容 返回
applyFilter TupleDomain 谓词 ConnectorTableHandle 或 empty
applyProjection 列映射 新 handle + 投影
applyLimit LIMIT n 无排序要求
applyTopN ORDER BY ... LIMIT 排序下推

成功下推后,handle 携带 约束getSplitscreatePageSource 只接触 缩小后的布局。Trino 文档说明:若 connector 不支持某下推,应返回 Optional.empty(),引擎保留对应 Filter / Sort / Limit 算子。

4.1 读湖时的两层裁剪

发生位置 与 Scan 关系
Layout 裁剪 Coordinator / Metadata fewer splits(manifest、partition)
Row group / page Worker / PageSource 单 split 内跳过 row group
引擎 Filter FilterOperator 无法下推的谓词、非确定性函数

lakehouse/18 的①②层在 打开文件前;③④在 PageSource 内;仍无法表达的谓词才出现在 FilterOperator


五、下推边界:何时必须留在 Scan 之上

下列情况通常 不能 完全下推,引擎保留 Filter / Project:

类别 示例 原因
非确定性 WHERE ts > now() 语义随执行时刻变
非内置函数 UDF、部分 connector 未映射函数 SPI 无等价
跨行语义 窗口、EXISTS 相关子查询未改写 需引擎算子
类型/ collation 与远端类型规则不一致 正确性
Security Row filter 与 column mask 引擎强制
表达式不在列上 WHERE a + b > 10 且源不支持 expr pushdown Project + Filter

Trino 文档 Pushdown 建议用 EXPLAIN 对比:若 aggregate 已下推,计划中 不出现 引擎侧 Aggregate;同理 Filter 下推成功后,remote 扫描 handle 带约束而 无多余 Filter 节点(取决于 EXPLAIN 格式版本)。

5.1 Lazy Materialization

优化器可能先只读 filter 列 + key 列,命中后再读 payload 列(lazy / late materialization)。这在 Trino 与 ClickHouse PREWHERE 思想相近(columnar-engine 读路径):减少无关列进入 CPU cache。是否启用取决于 planner 规则与 connector 是否支持 只读子集列 的两阶段读。

5.2 Dictionary Block 上的 Filter

Connector 若返回 DictionaryBlock第 7 篇),Filter 可先对 字典 求值,再通过索引过滤,避免展开全量字符串。引擎内 FilterOperator 需识别 block 编码;下推失败时仍可在引擎侧做 dictionary-aware 过滤。


六、FilterOperator 与 ProjectOperator

算子 输入 → 输出 典型工作
FilterOperator Page → Page(行数减少) 对保留谓词 batch 求值
ProjectOperator Page → Page(列变换) 表达式、cast、列重排

二者在 pipeline 中常紧挨 Scan;若谓词已下推,Filter 节点 被消除 或只做 残余谓词。Project 在 join 前可能多次出现(列裁剪、算 join key)。

Limit pushdownTopN pushdown 的边界:仅 LIMITORDER BY 时可用 applyLimit,结果顺序 任意;带排序必须 applyTopN 或引擎 TopN 算子(Trino Pushdown)。


七、与 PostgreSQL 的对照

机制 PostgreSQL Trino
扫描单位 SeqScan 逐行 Split + Page
列裁剪 Bitmap / index only scan(有限) connector projection
谓词下推 storage / FDW pushdown ConnectorMetadata.applyFilter
并行 parallel seq scan 多 Driver + 多 Worker

PG 执行器篇SeqScanExecQual 做 filter;Trino 把 能下推的 qual 尽量放进 TableHandle,减少 Page 过网络与算子链。


八、排查清单

  1. EXPLAIN Scan 节点:列数是否仍含未引用列?→ projection 未生效或 SELECT *
  2. Splits 数量:相对表文件数是否异常多/少?→ 分区谓词、manifest 裁剪(lakehouse/08 manifest)。
  3. Filter 节点残留:谓词是否含不支持函数或类型?→ 改 SQL 或换 connector 能力。
  4. EXPLAIN ANALYZE Physical Input:相对表总行数;与 lakehouse/18 漏斗对照。

九、边界


参考资料

类型 来源
文档 Trino 476+ — Connectors(SplitManager, PageSourceProvider, Metadata pushdown)
文档 Trino 476+ — Pushdown(projection, filter, TopN)
源码 trinodb/trinoTableScanOperator.java, ConnectorPageSourceProvider SPI
系列 lakehouse/18 查询引擎读湖

系列导航系列索引 · 上一篇:向量化与 morsel-driven · 下一篇:Hash Join 与 Hash Aggregation

同主题继续阅读

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

2026-07-07 · database / distributed

【分布式 OLAP 查询引擎】Iceberg 下推全链路:Planner 视角

与 lakehouse/18 分工:那边讲四层读湖漏斗是什么;本篇讲 Trino/Spark/DuckDB 在 SQL 优化链的哪一步把谓词变成 layout constraint、谁调用 Iceberg planning、split 如何携带残余谓词。引用官方文档与 lakehouse/18 本机 PyIceberg 实测,不伪造 Trino 计划输出。

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 查询引擎】统计信息与代价模型

Table/column 统计、NDV 与 histogram、Iceberg Puffin/manifest 统计来源;Trino CostCalculator 与 CPU/IO/network 权重;统计过期导致全表扫与 join 中间结果膨胀;对照 PostgreSQL pg_statistic。


By .