一、总体流程
1. SQL 解析与优化:SQL 经过 MySQL 原生优化器生成串行执行计划
2. 并行计划生成:并行查询优化器对串行计划进行评估,判断是否满足并行条件
3. 计划分解:将符合条件的表扫描拆分为多个范围分片,生成 PartialPlan
4. 并行执行:Worker 线程(简称 Worker)各自执行 PartialPlan,独立扫描分配到的数据分片
5. 结果收集:Leader 线程(简称 Leader)通过 Collector 操作汇总各 Worker 的结果,必要时做归并排序或去重
6. 返回客户端:Leader 将最终结果返回客户端
二、适用场景
·多表关联查询:JOIN 查询涉及大表扫描
·聚合分析:GROUP BY + 聚合函数的大数据量查询
·排序查询:需要对大量数据进行 ORDER BY 排序
·分区表查询:按分区键并行扫描各分区
·含子查询的复杂 SQL:子查询可并行预先执行
三、并行计划生成
并行查询在 MySQL 原生优化器之后工作。MySQL 先产生串行执行计划,并行查询优化器再对该计划进行分析,决策过程与代价模型详见 并行查询优化器。
并行计划生成的关键检查包括:
1. 参数限制检查:max_parallel_workers 必须大于0、max_parallel_degree 必须有效或存在 PARALLEL HINT,否则直接退出
2. 代价评估:检查串行执行代价是否超过 parallel_plan_cost_threshold,parallel_query_switch 中 force=on 或存在 PARALLEL HINT 时跳过此检查
3. 并行安全检查:遍历查询中所有表达式,任一表达式不支持并行执行则拒绝并行
4. 分布策略选择:为每张表选择分布类型(详见 并行查询优化器 中的分布模型章节)
5. JOIN 路径组合:对 outer/inner 两侧路径,剪枝不兼容组合,必要时插入 Collector 桥接
6. 最优路径选择:根据代价选择路径,优先选 HINT 匹配最多的路径;系统变量 parallel_plan_compare_serial_cost 控制串行路径是否参与比较
7. Slice 划分:沿最优路径在 Collector 处切分,根 Slice 运行于 Leader,每个子 Slice 对应一个 PartialPlan
四、Slice 与 PartialPlan
并行计划将原始计划按 Slice 进行分片。每个 Slice 是一个独立的执行单元:
·Slice 0(Leader 端):在 Leader 上执行,负责汇总结果。包括 Collector 操作和需要全局视角的操作
·Slice 1 ~ N(Worker 端):在 Worker 上并行执行,每个 Worker 可能包含并行扫描(支持多张表的并行扫描)
例如一个简单的 SELECT * FROM t1 WHERE a > 0 的并行计划:
·Slice 1:4个 Worker 各自扫描 t1 的1/4数据范围
·Slice 0:Leader 通过 Collector 收集4个 Worker 的结果
对于带 JOIN 的查询 SELECT * FROM t1 JOIN t2:
·Slice 1:4个 Worker 并行扫描 t1,各自与 t2 在本 Worker 内完成 Hash Join
·Slice 0:Leader 通过 Collector 收集4个 Worker 的 JOIN 结果
注意:说明:
注意:常见场景为根 Slice 以及一层子 Slice 的两层结构,详见 并行查询优化器。
五、并行扫描
并行查询支持两种并行扫描方式,优化器根据表结构和查询特征自动选择。可通过 PARALLEL HINT 显式指定扫描类型,详见 优化器 Hints。
六、Dynamic Range Scan(动态范围并行扫描)
将表数据按主键范围动态切分为 N 个连续分片。每个 Worker 负责一个分片的扫描。
适用场景:
·未分区或无需按分区分片的普通表
·带范围条件的查询(WHERE id BETWEEN X AND Y),优化器可进一步剪枝无关分片
工作方式:
1. 优化器估算表的总行数和数据分布
2. 将 Key 空间均匀切分为 N 个区间(N 远大于系统变量 max_parallel_degree)
3. 每个 Worker 从 N 个区间中动态争抢工作,防止数据倾斜
七、Partition Scan(分区并行扫描)
按物理分区将数据分片,每个分区分配给一个 Worker。
适用场景:
·使用 HASH 或 RANGE 分区的分区表
·希望利用分区裁剪的查询,例如针对分区键的等值 JOIN(WHERE partition_key = X)
工作方式:
1. 优化器识别表中可用的分区列表
2. 将各分区均匀分配给 Worker
3. Worker 扫描分配给自己的分区
并行扫描方式选择:
·优化器决策:
·分区表且分区数足够多(≥ 并行度),优先使用 Partition Scan
·非分区表或分区数少,使用 Dynamic Range Scan
·通过 HINT 显式指定:SELECT /*+ PARALLEL(t PARTITION) */ 或 SELECT /*+ PARALLEL(t DYNAMIC_RANGE) */,详细参考 优化器 Hints
八、Gather(结果收集)
Gather 是 Leader 线程从多个 Worker 收集结果的算子,它属于一种 Collector。它位于 Leader 端计划的关键位置,负责将并行执行的结果汇总。执行计划中 Gather 节点的具体输出格式详见 并行计划解读。
Gather 支持多种数据处理模式:
| 模式 | 适用场景 | 说明 |
| 普通 Gather | 无需保证顺序 | 简单将各 Worker 结果逐行收集并传递给上层算子 |
| Merge Sort | 需要 ORDER BY 输出 | 收集时对各 Worker 已排序的结果做归并排序。Worker 端做局部排序,Leader 端做归并 |
Gather 也支持对结果进行流式或物化输出(上层算子需要重复扫描时物化)。
九、并行聚合
GROUP BY 聚合操作在并行执行中有多种策略,优化器根据查询特征自动选择最优方案。
十、一阶段聚合
Worker 只负责扫描数据,数据汇聚到 Leader 后,由 Leader 执行聚合。
适用场景:
聚合函数或 GROUP BY 表达式不满足下推条件(如带 DISTINCT 的聚合、不可两阶段的 GROUP_CONCAT / LISTAGG 等),无法将聚合下推到 Worker 时的兜底策略。
十一、两阶段聚合(默认策略)
Worker 先执行局部聚合,接着 Gather 汇总, Leader 执行最终聚合。
流程:
1. 各 Worker 并行扫描数据,对各自范围内的数据执行局部 GROUP BY
2. Worker 将局部聚合结果发送给 Leader
3. Leader 对来自所有 Worker 的中间结果再次执行 GROUP BY,得到最终聚合结果
十二、完全下推聚合
当优化器可以确定各 Worker 间的 GROUP BY 键值不会重复时,将聚合完全下推到 Worker。此时 Leader 无需再次 GROUP BY,只需做简单汇总。
开启条件:
·parallel_query_switch 中 full_grouping_pushdown 选项已开启(默认开启)
·聚合函数和 GROUP BY 表达式满足下推安全性
·数据的分布与 GROUP BY 表达式兼容,每个 Worker 上的分组数据完整
·对于 Partition Scan,需要分区键是 GROUP BY 列的前缀
·对于 Dynamic Range Scan,需要表上的 Distinct Index 与 GROUP BY 列有公共前缀
十三、下推排序(默认)
Worker 先对各自结果执行排序,Leader 通过 Gather Merge Sort 归并:
1. 各 Worker 使用本地排序算法(filesort)对各自数据排序
2. Leader 启动 Merge Sort,同时从 N 个 Worker 的有序结果流中读取
3. 通过优先队列按 sortkey 升序归并,逐行返回
优势:充分利用多核并行排序能力,加速大数据量排序
十四、非下推排序
当排序列无法下推(排序表达式包含非并行安全的函数、排序列是常量),数据先通过 Collector 到 Leader,再在 Leader 上串行排序。