继续往下学 StarRocks,我还是想保持上一篇的方式:不急着记一堆架构名词,先弄明白每个名词到底在解决什么问题。
如果你是第一次看到这个系列,还没看过上一篇,可以先从这里开始:
👉《StarRocks 是什么?为什么有了 MySQL 还需要它》
上一篇我们讲清了 MySQL 和 StarRocks 的分工。
MySQL 更擅长处理一笔笔具体业务,StarRocks 更擅长分析大量数据。
但问题也跟着来了:
同样是一条 SQL,StarRocks 为什么能让多台机器一起计算?
这背后最关键的概念,就是MPP。
这篇不追求把 MPP 的所有细节讲完。
我们先只解决一件事:一条分析 SQL,是怎样被拆开、并行执行,再合成最终结果的。
先从一条看起来普通的 SQL 开始
假设运营在报表平台中选择了“本月各城市销售额”。
报表系统在背后可能会向 StarRocks 发出这样一条 SQL:
SELECT
city,
SUM(amount) AS sales
FROM orders
WHERE order_time >= '2026-07-01'
AND order_time < '2026-08-01'
GROUP BY city;
如果 orders 表里只有几千行数据,这条 SQL 在一台机器上执行,通常没有什么压力。
但如果订单明细持续增加,需要扫描的数据越来越多,单台机器就要独自完成这些工作:
数据量较小时,单台机器通常可以独立完成这些工作。
随着数据增多,查询性能不只取决于 SQL 写法和执行计划,还会受到单机 CPU、内存、磁盘 I/O 等资源上限的约束。
既然单机资源存在上限,能不能让几台机器共同处理同一条查询?
可以,这就是理解 MPP 的入口。
图 1:单机执行由一台机器处理全部数据;MPP 将任务分给多个执行节点并行处理。
MPP 到底是什么意思
MPP 的全称是Massively Parallel Processing,通常翻译为“大规模并行处理”。
先别被这个名字吓到。
可以把它理解成:
一项很大的计算任务,不再只交给一台机器,而是拆成许多较小的任务,让多台机器同时处理。
比如仓库里有 300 个货架,需要统计每种商品的数量。
一种做法是安排一个人从第一个货架数到最后一个货架。
另一种做法是安排三个人:
甲:统计 1~100 号货架
乙:统计 101~200 号货架
丙:统计 201~300 号货架
三个人各自得到一份统计结果,最后再把结果汇总。
这就是最简单的“拆分、并行、汇总”。
当然,数据库执行查询远比清点货架复杂。
但对初学者来说,先抓住这个主干就够了。
一条 SQL 进入 StarRocks 后发生了什么
为了讲清流程,我们先认识两个角色:
-
FE:接收 SQL,理解查询要求,生成并调度执行计划;
-
BE:执行具体的数据读取和计算任务。在存算一体架构中,BE 还负责保存数据。
可以暂时把 FE 想成负责安排工作的调度者,把多个 BE 想成真正处理数据的执行者。
但这个类比只用于入门理解。FE 不是简单地把 SQL 原文复制给每台 BE,而是先把 SQL 转换成可以执行的计划。
整个过程可以压缩成四步。
第一步:FE 先理解 SQL 要做什么
FE 收到查询后,会进行解析、分析和优化。
它需要弄清楚:
-
查询哪张表;
-
读取哪些列;
-
使用什么过滤条件;
-
是否需要分组、聚合、关联或排序;
-
数据位于哪些执行节点;
-
各个计算阶段应该怎样组织。
最后,FE 生成一份物理执行计划。
可以把它理解成一张施工图:谁先读取数据,谁负责聚合,中间结果怎样传递,最终结果从哪里返回。
第二步:执行计划被划分成多个执行阶段
StarRocks 会按照查询语义,把执行计划划分为不同的逻辑执行单元,也就是官方文档中常见的Query Fragment,下文简称 Fragment。
Fragment 不是把 SQL 文本从中间剪开。
它更像执行计划中的一个阶段或一段子计划。一个 Fragment 里面可以包含多个算子,例如扫描、过滤、读取指定列和聚合。
对这条按城市统计销售额的查询,可以先简化为两个执行阶段:
Fragment A(阶段一)
扫描订单 → 按时间过滤 → 读取 city、amount → 本地部分聚合
↓ 数据交换:按照 city 重新分发中间结果
Fragment B(阶段二)
合并相同 city 的部分结果 → 完成最终聚合 → 返回结果
两个阶段之间需要交换数据。StarRocks 会按照下一阶段的需要,对中间结果进行传递或重新分布。本篇只要把它理解成“阶段之间传递数据”即可,不再引入更细的术语。
所以,不能把它理解为:
BE 1 只负责扫描
BE 2 只负责过滤
BE 3 只负责聚合
更接近实际情况的是:Fragment A 这一整个阶段会在多个 BE 上并行执行。BE 1、BE 2、BE 3 都执行“扫描 → 过滤 → 本地部分聚合”,只是各自处理的数据不同。
至于 StarRocks 内部怎样把同一个阶段调度成更细的执行单位,本篇先不展开。现在只需要记住:同一组计算动作,处理不同部分的数据。
第三步:多个 BE 同时计算
假设订单数据分布在三个 BE 上。
FE 把 Fragment A 这一阶段安排到多个 BE 上并行执行。查询开始后,各个 BE 同时处理自己负责的那部分数据:
BE 1:扫描数据 A → 过滤 → 部分聚合
BE 2:扫描数据 B → 过滤 → 部分聚合
BE 3:扫描数据 C → 过滤 → 部分聚合
它们不必都把原始明细先发送到某一台机器,再由那台机器从头计算。
更常见的做法是,每个 BE 先在本地完成过滤和部分聚合。
例如:
BE 1:上海 120 万,北京 80 万
BE 2:上海 90 万,广州 70 万
BE 3:北京 60 万,广州 50 万
这样向后传递的是已经缩小过的中间结果,而不是所有原始订单。
第四步:交换中间结果,下一阶段继续计算
多个 BE 得到部分结果后,StarRocks 可以按照 city 重新分发,让相同城市的数据进入对应的下游计算任务。
Fragment B 再继续合并:
上海:120 万 + 90 万 = 210 万
北京:80 万 + 60 万 = 140 万
广州:70 万 + 50 万 = 120 万
完成最终聚合后,StarRocks 再把查询结果返回给报表系统。
为了便于入门理解,图中把 Fragment B 画成了一个整体阶段。这不代表最终聚合固定由一台 BE 完成,只是暂时省略更细的并行调度过程。
图 2:FE 生成分布式执行计划;Fragment A 在多个 BE 上处理不同数据,中间结果经过数据交换后交给 Fragment B 继续聚合。
回头看,一条 SQL 并没有变成三条不同的业务 SQL。
变化的是它的执行方式:
从一台机器处理全部数据,变成多个执行节点分别处理部分数据。
为什么“先在本地算一部分”很重要
刚开始理解 MPP 时,我以为并行计算就是把所有数据平均分给几台机器。
后来才意识到,这只说对了一半。
多台机器一起计算,意味着机器之间还要交换数据。
如果每个 BE 都把大量原始订单通过网络发送出去,网络传输和最终汇总很可能变成新的瓶颈。
所以,能在本地完成的过滤和聚合,应尽量在本地先做。
仍然以销售额统计为例。
假设某个 BE 上有大量上海订单。它没有必要把这些订单一条条发送出去,只要先算出“上海订单金额小计”,再发送这个小计即可。
原始明细越多,本地预先处理能够减少的数据传输通常越有价值。
这也是为什么查看分析型数据库的执行过程时,我们不能只看“用了几台机器”,还要看数据在哪里被过滤、在哪里被聚合、节点之间移动了多少数据。
机器越多,查询就一定越快吗
不一定。
这是理解 MPP 时非常重要的边界。
多台机器并行执行,确实能让一条查询使用更多 CPU、内存和磁盘资源,但并不代表节点数量翻倍,查询时间就一定减半。
实际效果还会受到很多因素影响:
-
数据是否分布均匀;
-
过滤条件能否尽早生效;
-
中间结果需要传输多少;
-
是否存在某个特别慢的节点;
-
GROUP BY、JOIN、排序等计算是否产生大量数据交换;
-
查询本身是否足够大,值得拆分和调度。
如果一条查询只处理几十行数据,协调多台机器的成本可能比计算本身还明显。
如果大量数据集中在少数节点上,其他节点很快完成任务,也只能等待最慢的节点。
这就像三个人一起搬货:
如果货物分得均匀,大家可以同时完成;
如果大部分货物都分给了一个人,另外两个人再快也没有用。
所以更准确的说法不是“MPP 一定快”,而是:
MPP 让大型查询有机会同时利用多台机器的资源,但最终性能仍取决于数据分布、执行计划和数据交换成本。
初学者最容易产生的三个误解
误解一:MPP 会把一条 SQL 变成多条独立 SQL
不是。
用户提交的仍然是一条完整 SQL。StarRocks 会为它生成分布式执行计划,让多个 BE 处理不同部分的数据,而不是分别执行多条独立 SQL。
误解二:FE 负责完成所有计算
不是。
FE 主要负责查询规划和调度,真正读取和处理大量数据的是 BE;存算分离架构下则由 CN 承担计算。
这一篇为了保持主线简单,后面仍以 FE 和 BE 为例。
误解三:只要增加 BE,任何查询都会等比例变快
也不是。
节点增加后,系统获得了更多计算资源,但查询能否利用这些资源,还取决于任务是否能有效并行,以及是否存在数据倾斜、网络传输等瓶颈。
我现在怎样记住 MPP
写到这里,可以先不背 Fragment、Pipeline、Operator 等更多术语。
只记住三个字:
拆:FE 把查询转换为执行计划,并拆成可调度的计算任务
并:多个 BE 同时处理各自负责的部分数据
合:中间结果继续聚合,形成最终查询结果
这就是 MPP 最值得先建立的整体认识。
再回到开头那条 SQL:
SELECT city, SUM(amount)
FROM orders
GROUP BY city;
我们看到的只是一条 SQL。
StarRocks 在背后看到的,却是一组可以被规划、拆分、调度和并行执行的计算任务。
这正是它能够处理大规模分析查询的重要基础。
下一篇,我们继续沿着这条 SQL 往下看:
FE 和 BE 到底分别负责什么?一条查询在 StarRocks 集群中经过了哪些节点?