一条 SQL 穿过集群:Presto 为什么能把很多数据源当成一张表

如果只用一句话解释 Presto,我会这么说:Presto 是一个分布式 SQL 查询引擎,用来把很多地方的数据临时接到同一个 SQL 执行层里查询

这句话里最重要的是两个词:查询引擎,以及很多地方的数据。Presto 的重点不是自己存多少数据,而是让你可以用 SQL 去查询已经存在于 Hive、Iceberg、MySQL、Kafka、Elasticsearch、对象存储或其他系统里的数据。

所以,理解 Presto 不要先把它想成 MySQL、ClickHouse 或 Doris 这样的数据库,而要把它想成一个「分布式查询调度中心」:用户提交 SQL,Coordinator 负责理解和拆解这条 SQL,Worker 负责并行干活,Connector 负责和不同数据源打交道,最后把结果汇总回来。

一、先给一个准确定位

Presto 的定位可以拆成三层。

关键词含义说明
SQL 查询引擎入口是 SQL,输出是查询结果它关心怎么把 SQL 变成可执行计划
分布式不是单机执行,而是很多 Worker 一起执行一张大表会被拆成很多 Split 并行扫描
联邦查询可以通过 Connector 查询不同数据源同一条 SQL 可以访问 Hive、MySQL、Kafka 等系统

更工程化一点说:Presto 接收一条 SQL,把它解析成查询计划,再把查询计划切成多个 Stage、Task 和 Split,分发到多个 Worker 上执行。Worker 从不同 Connector 读取数据,在本地做过滤、投影、聚合、Join,然后通过 Exchange 在节点之间交换中间结果,最后由 Coordinator 汇总返回。

这就是 Presto 的核心:它不是数据的最终归宿,而是数据查询时的统一执行现场

二、一个直观例子:为什么需要 Presto

假设公司里有这些数据:

  • 用户行为日志在 Hive 或 Iceberg 表里;
  • 订单明细在 MySQL 里;
  • 实时曝光和点击消息在 Kafka 里;
  • 搜索索引和部分画像在 Elasticsearch 里。

现在你想临时回答一个问题:今天每个城市的访问用户里,有多少人产生了订单?如果不用 Presto,常见做法是先把 MySQL 订单同步到数仓,再建临时表,再跑 Hive 或 Spark 任务。这个流程适合稳定报表,但对临时探索来说太重。

Presto 的做法是:不一定先搬数据,而是用 Connector 直接连接不同数据源,然后在查询时把它们接到同一个 SQL 世界里。

SELECT
  u.city,
  count(DISTINCT o.order_id) AS order_cnt
FROM hive.dw.user_log u
JOIN mysql.order_db.orders o
  ON u.user_id = o.user_id
WHERE u.dt = '2026-06-14'
GROUP BY u.city;

这条 SQL 看起来像是在查同一个数据库里的两张表,但实际上一张表可能在 Hive,另一张表可能在 MySQL。Presto 负责把这件事变成一个分布式查询任务:能下推的过滤尽量下推,能并行扫描的地方并行扫描,需要 Join 的地方通过网络把数据重新分布到合适的 Worker 上。

这也是 Presto 最吸引人的地方:数据可以分散,查询入口可以统一

三、Presto 不是什么

为了避免误解,先讲 Presto 不是什么。

它不是传统数据库

MySQL 这类数据库通常同时负责存储、索引、事务、日志、锁、查询优化和执行。Presto 不以自有存储为中心,也不负责像 MySQL 那样管理 redo log、binlog、二级索引和强事务。

Presto 更像一个计算层:拿到 SQL,生成计划,调度 Worker,从外部数据源读取数据并计算结果。所以说它是查询引擎,比说它是数据库更准确。

它不是 Hive 的简单替代品

Hive 更偏离线批处理,适合稳定 ETL、大规模离线任务和数仓分层建设。Presto 更偏交互式分析,适合临时查数、BI 查询、数据探索和跨源联合查询。

Hive:更适合大批量、离线、稳定产出
Presto:更适合交互式、临时、多源查询

它也不是 Spark

Spark 是通用分布式计算框架,可以写复杂程序,做 ETL、机器学习、流处理和批处理。Presto 更聚焦 SQL 查询服务。

Spark:我是一个通用计算框架
Presto:我是一个分布式 SQL 查询引擎

如果你要写复杂的数据处理流程,Spark 通常更合适;如果你要快速用 SQL 查已有数据,Presto 通常更直接。

四、核心结构:Coordinator、Worker 和 Connector

Presto 集群里最重要的是三个角色。

角色主要职责可以类比成
Coordinator接收 SQL、解析语义、生成查询计划、调度 Worker、汇总结果大脑和调度中心
Worker执行 Task,扫描数据,运行 Operator,处理过滤、聚合、Join、排序真正干活的计算节点
Connector把外部数据源适配成 Presto 能理解的 Catalog、Schema、Table、Split 和类型连接不同数据系统的驱动
Client SQL
    ↓
Coordinator:parse / analyze / optimize / schedule
    ↓
Workers:tasks / drivers / operators
    ↓
Connectors:Hive / Iceberg / MySQL / Kafka / Elasticsearch ...
    ↓
Storage systems

Coordinator 不应该承担大量数据处理。它更像大脑,负责计划和调度。真正消耗 CPU、内存、网络和 IO 的地方,主要在 Worker。Connector 则是 Presto 能跨数据源查询的关键;没有 Connector,Presto 只是一个 SQL 执行框架,有了 Connector,它才变成「SQL on everything」。

五、一条 SQL 怎么执行

以一条简单 SQL 为例:

SELECT region, count(*)
FROM hive.dw.orders
WHERE dt = '2026-06-14'
GROUP BY region;

它在 Presto 里大概会经历这些步骤。

SQL 文本
  ↓
解析成语法树
  ↓
语义分析:表是否存在,字段是否存在,类型是否匹配
  ↓
生成逻辑计划
  ↓
优化计划:分区裁剪、列裁剪、谓词下推、聚合拆分
  ↓
生成分布式执行计划
  ↓
拆成多个 Stage
  ↓
每个 Stage 拆成多个 Task
  ↓
Task 分配到 Worker
  ↓
Worker 读取 Split
  ↓
Operator 执行 scan / filter / project / aggregation / join
  ↓
不同 Worker 通过 Exchange 交换数据
  ↓
Coordinator 返回结果

这条链路里有几个概念尤其重要。

Split:数据切片

Presto 不会让一台机器扫完整张大表,而是把输入数据拆成很多 Split。对于 Hive 表,一个 Split 可能对应一个文件、一段文件,或者某种可并行读取的数据片段。

orders 表
  ├── split 1
  ├── split 2
  ├── split 3
  ├── split 4
  └── ...

这些 Split 会被分配给不同 Worker 并行处理。Presto 的并行能力,首先就来自这里。

Stage、Task、Driver、Operator

Stage 是分布式执行计划里的阶段。比如一个查询可能先扫描并做局部聚合,再把中间结果汇总成最终聚合。每个 Stage 会被拆成多个 Task,Task 运行在 Worker 上。

Task 内部还有更细的执行单元。Driver 把一串 Operator 串起来,Operator 才是真正处理数据的算子,比如 TableScan、Filter、Project、HashJoin、Aggregation、OrderBy、Exchange。

Query
  └── Stage
        └── Task on Worker
              └── Driver
                    ├── TableScanOperator
                    ├── FilterOperator
                    ├── ProjectOperator
                    └── AggregationOperator

所以,一条 SQL 并不是被某个神秘黑盒一次性执行完,而是被拆成许多小的、可以并行调度的执行单元。

Exchange:很多慢查询真正慢的地方

Presto 查询不只是读数据,还经常需要在 Worker 之间交换数据。比如 Join 和 Group By 都可能要求相同 key 的数据被送到同一批 Worker 上。

Worker A:user_id 1, 3, 5
Worker B:user_id 2, 4, 6

按照 user_id hash 重新分发

Worker A:user_id 1, 2
Worker B:user_id 3, 4
Worker C:user_id 5, 6

这个过程就是 Exchange。它会消耗网络、CPU 序列化、内存和队列等待。很多 Presto 慢查询,慢的不是 Table Scan,而是 Join、Group By、Order By 引发的大量 Exchange。

六、Connector 为什么关键

Connector 是 Presto 能够查询多种数据源的根本原因。它要回答几个问题:

  • 这个数据源有哪些 Catalog、Schema、Table?
  • 每张表有哪些列,列类型是什么?
  • 这张表能被拆成哪些 Split 并行读取?
  • 哪些过滤条件、列裁剪、聚合或 limit 可以下推到底层?
  • 底层系统的权限、分区、文件格式、统计信息如何映射给 Presto?

比如访问 Hive 时,Presto 需要从 Metastore 读取表结构和分区信息,再从 HDFS 或对象存储读取 ORC/Parquet 文件。访问 MySQL 时,Presto 需要把远端表映射成可查询表,并尽可能把简单过滤下推给 MySQL。访问 Kafka 时,Connector 还要把 Topic 里的消息解释成表结构。

所以 Presto 的性能不只取决于执行引擎,也取决于 Connector 做得好不好。一个优秀的 Connector 能减少扫描、减少网络传输、保留底层系统的能力;一个很薄的 Connector 只能把大量数据拉上来再算,性能自然会差。

七、Presto 为什么快

Presto 的快,主要来自几件事叠加。

  • 分布式并行:大表被拆成很多 Split,多个 Worker 同时扫描和计算。
  • Pipeline 执行:数据尽量边读边过滤、边投影、边聚合,而不是每一步都落盘。
  • 列裁剪:SQL 只查三列,底层 ORC/Parquet 就尽量只读这三列。
  • 谓词下推:比如 dt 分区条件能下推时,就只读对应分区,而不是全表扫描。
  • 局部聚合:先在各 Worker 本地做 partial aggregation,再做 final aggregation,减少跨节点传输。
  • 常驻服务:Worker 是常驻进程,不需要像某些批任务一样每次重新启动一套执行环境。

例如下面这条查询:

SELECT city, count(*)
FROM hive.dw.orders
WHERE dt = '2026-06-14'
GROUP BY city;

如果表按 dt 分区,文件是 Parquet 或 ORC,查询只需要 city 这一列,Presto 就可能只读当天分区里的少数列,并且先在每个 Worker 本地算出一部分 count,再汇总最终结果。这就是它适合交互式分析的原因。

八、Presto 什么时候会慢

Presto 不是魔法。它能把合理的查询并行化,但不能凭空让数据变少。下面这些情况经常会让 Presto 慢下来。

现象常见原因排查方向
扫描量巨大没带分区条件、列裁剪失效、文件格式不合适看 input rows/input bytes,检查 where 条件和表分区
Planning 很慢分区太多、元数据服务慢、小文件过多看 planning time,检查 Metastore、分区数量和文件数量
Join 很慢大表 Join 大表、Join key 倾斜、build side 过大看各 Stage 数据量,检查 Join 顺序和 key 分布
Exchange 很重Group By 或 Join 需要大量重分布看 network bytes、blocked time、Stage 间数据传输
内存压力大高基数聚合、排序、窗口函数、Hash Join看 peak memory、spill、失败 Query 的错误类型

尤其要注意小文件和数据倾斜。小文件会让 Coordinator 和 Worker 花大量时间做元数据处理和任务调度;数据倾斜会让某几个 Worker 处理远多于其他节点的数据,整个查询只能等最慢的节点完成。

九、和 Hive、Spark、ClickHouse、Doris 的边界

Presto 经常和 Hive、Spark、ClickHouse、Doris 放在一起比较,但它们解决的问题不完全一样。

系统更适合和 Presto 的关系
Hive离线数仓、批量 SQL、稳定 ETLPresto 常通过 Hive Connector 读取 Hive 表,适合更交互的查询
Spark通用批处理、复杂 ETL、机器学习、流批任务Spark 更像计算框架,Presto 更像 SQL 查询服务
ClickHouse高性能列式 OLAP、明细聚合、单系统内查询ClickHouse 自带存储,Presto 更强调跨源联邦查询
Doris实时数仓、报表分析、向量化 OLAP 查询Doris 是数据库形态,Presto 是计算层形态
Iceberg/Hudi/Delta Lake数据湖表格式、快照、Schema 演进、增量语义Presto 可以作为访问这些表格式的 SQL 引擎之一

如果核心问题是「数据在很多地方,希望临时用 SQL 统一查」,Presto 很合适。如果核心问题是「我要建设一个高并发、低延迟、强存储优化的 OLAP 服务」,ClickHouse 或 Doris 这类系统可能更合适。如果核心问题是「复杂批处理、机器学习训练、长链路 ETL」,Spark 仍然有不可替代的生态优势。

十、适用场景:什么时候应该选 Presto

选不选 Presto,关键不是看它能不能跑 SQL,而是看你的问题是不是符合它的能力模型:数据已经存在于多个系统里,查询以读为主,希望用 SQL 快速探索,并且可以接受秒级到分钟级的分析延迟

1. 临时分析和数据探索

这是 Presto 最典型的场景。比如运营、分析师或工程师临时想看一个指标,不确定这个分析以后会不会固化成报表。如果每次都先建表、同步数据、跑离线任务,成本太高;用 Presto 直接查 Hive、Iceberg 或 MySQL,能更快验证想法。

适合的问题:
今天某个活动的用户转化怎么样?
某个城市的订单异常是不是集中在某类商家?
新版本上线后,某个行为日志有没有明显变化?

这类查询的特点是:问题变化快,SQL 变化快,结果主要用于判断方向,不一定需要沉淀成稳定数据资产。

2. 跨数据源联合查询

如果数据分散在多个系统里,Presto 的价值会非常明显。比如用户维表在 MySQL,行为日志在 Hive,实时事件在 Kafka,画像结果在 Elasticsearch。你不一定想为了一个临时问题把所有数据都同步到同一个地方。

Presto 可以通过不同 Connector 把这些数据源接到同一条 SQL 里,让你先完成分析,再决定是否要把某条链路产品化、报表化或数仓化。

数据位置典型数据Presto 的作用
Hive / Iceberg日志、明细、离线宽表大规模扫描和聚合
MySQL维表、配置、业务状态和数仓事实数据做补充 Join
Kafka实时消息、埋点流用于排查、抽样和近实时观察
Elasticsearch搜索索引、文档、画像和结构化数据做联合分析

3. 数据湖和开放表格式查询

在数据湖场景里,数据通常存在 HDFS 或对象存储上,表格式可能是 Hive、Iceberg、Hudi 或 Delta Lake。Presto 很适合作为这些数据的交互式 SQL 查询入口。

它的优势在于:计算和存储分离,底层数据可以继续由数据湖管理,Presto 负责查询执行。这样既能保留开放存储格式的灵活性,又能给分析和 BI 提供统一 SQL 入口。

4. BI 和自助取数

很多公司会把 Presto 接到 BI 平台后面,让分析师通过图表工具查询数仓或数据湖。这个场景的关键不是单条 SQL 极致性能,而是让更多人用统一入口访问可信数据。

不过 BI 场景一定要配合资源治理。看板刷新、临时拖拽、全表扫描、高基数 group by 如果混在一起,很容易互相影响。因此 Presto 适合做 BI 查询入口,但不适合在没有 Resource Group、超时、并发限制和 SQL 规范的情况下裸奔。

5. 数据校验和问题排查

Presto 也很适合做数据链路排查。比如离线表和在线库口径是否一致,某个分区数据是否缺失,上游日志是否延迟,某个维表字段是否和明细事实能对齐。

典型排查:
Hive 明细表和 MySQL 状态表对账
新老 Iceberg 表抽样比对
日志表按小时检查是否缺分区
某个订单在业务库和数仓里的状态是否一致

这类查询通常不需要把结果长期存储下来,只需要快速连接多个数据源、对比样本、定位问题。Presto 的跨源能力正好适合这种工程排障。

6. 数据产品的统一查询层

如果一个内部数据产品要支持多种底层存储,又希望上层用户尽量只感知 SQL,Presto 可以作为统一查询层。上层看到的是 Catalog、Schema 和 Table;下层可以是 Hive、Iceberg、MySQL 或其他系统。

这种模式适合读多写少、查询形态相对分析化的数据产品。但要注意,Presto 只解决查询执行,不自动解决指标口径、权限、血缘、数据质量和成本归因。这些仍然需要数据平台自己建设。

十一、不适用场景:什么时候不要选 Presto

Presto 不是万能查询层。下面这些场景,即使它能跑,也通常不是最优选择。

不适合的场景原因更常见的选择
高频在线交易Presto 不负责强事务、行级写入和低延迟事务控制MySQL、PostgreSQL、TiDB 等 OLTP 系统
毫秒级在线点查Presto 的调度和分布式执行开销不适合极低延迟请求Redis、KV、搜索引擎、专用在线服务
复杂长链路 ETLPresto 更偏查询服务,不是通用作业编排和复杂计算框架Spark、Flink、Hive、调度系统
极高并发报表服务如果每个用户都频繁触发重查询,成本和资源隔离压力很大Doris、ClickHouse、预聚合、缓存层
无治理的大查询平台少数全表扫描或大 Join 会拖垮共享集群先建设资源组、限流、审计和 SQL 规范
需要强索引优化的点查分析Presto 主要依赖底层数据源和列式/分区能力,不是索引型数据库ClickHouse、Elasticsearch、专用索引系统

一个简单判断方法是:如果你的查询主要是大范围读、分析、聚合、跨源 Join,Presto 值得考虑;如果你的请求主要是小范围点查、高并发在线服务、强事务写入、稳定复杂 ETL,Presto 通常不是第一选择。

十二、生产里怎么用好 Presto

Presto 进入生产后,重点不只是把集群搭起来,而是治理查询行为。

  • 把场景分层:BI 看板、临时分析、数据校验、低频报表不要都挤在同一个资源池里。
  • 用 Resource Group 做治理:按用户、来源、查询类型拆资源组,限制并发、排队、内存和单查询资源上限。
  • 推动分区和列式存储:对大表来说,正确的分区、排序、文件大小和 ORC/Parquet 格式比 SQL 小技巧更重要。
  • 限制危险 SQL:没有分区条件的大表扫描、笛卡尔积、无界排序、高基数 distinct,都应该有审计或拦截机制。
  • 看懂 Query Plan:使用 EXPLAIN、EXPLAIN ANALYZE、Web UI、JMX 指标观察 Stage、Task、Input、Output、Blocked Time 和 Memory。
  • 把小文件治理前置:小文件会拖慢元数据加载和 Split 调度,最终表现为 Planning 慢、Worker 空转和吞吐下降。

一个健康的 Presto 集群,应该让大多数人可以快速做探索式分析,同时不允许少数危险查询拖垮所有人。这也是 Resource Group、队列、限流、超时、查询审计和 SQL 规范真正发挥作用的地方。

十三、几个常见误解

误解一:Presto 能替代数仓

Presto 可以查询数仓,但它不等于数仓。数仓还包括数据建模、分层、口径、权限、血缘、质量、调度、成本治理和生命周期。Presto 只是其中的查询入口和执行层。

误解二:加 Worker 就一定变快

如果瓶颈是扫描和并行度,加 Worker 可能有帮助;如果瓶颈是 Coordinator Planning、元数据、小文件、Join 倾斜、单点数据源吞吐或网络 Exchange,加机器只会让问题变得更贵。

误解三:SQL 能跑就说明写得对

在 Presto 里,SQL 能跑只是第一步。你还要看扫描了多少数据、是否触发跨节点重分布、是否利用分区、是否把小表放到 build side、是否出现数据倾斜,以及这条查询会不会影响同集群里的其他人。

结语

Presto 是为了解决一个非常现实的问题出现的:数据越来越分散,但人仍然希望用一条 SQL 快速分析它们

它不负责成为所有数据的家,而是负责让不同数据源可以被统一查询。它快,是因为分布式并行、Pipeline 执行、列裁剪、谓词下推和局部聚合;它慢,通常是因为扫描数据太多、Join 太重、Exchange 太大、数据倾斜、小文件太多,或者资源治理不足。

所以真正理解 Presto,要抓住这句话:Presto 不是数据库本身,而是一个把很多数据源接入同一个 SQL 世界的分布式查询引擎。它最适合把分散数据快速接到一起做分析,而不是替代所有数据库、数仓和计算框架。

延伸阅读