并行度调优
并行度(parallel_pipeline_task_num)控制单个 Fragment 在 BE 内执行时使用的工作任务数,是充分利用多核 CPU、降低查询延迟的关键参数。
调优前自检 Checklist
- 已确认 BE 的 CPU 核数(决定并行度上限)。
- 已通过 Profile 或监控判断瓶颈类型(CPU 密集 / 扫描密集 / 调度开销)。
- 已了解当前查询场景(点查、JOIN/聚合、压测、复杂查询)。
- 默认值(0,即 CPU 核数的一半)下性能确实不达预期。
核心概念
- MPP 并行:每条查询在多个 BE 上并行执行。
- BE 内并行:单个 BE 内通过多线程加速 Fragment 执行。
parallel_pipeline_task_num:单个 Fragment 在执行时使用的工作任务数,默认0表示 BE CPU 核数的一半。- 适用语句:所有 Query、DML、DDL 均支持并行执行。
调优原则
并行度并非越大越好:
- 提高并行度可充分利用多核资源、降低单查询延迟。
- 但会引入额外的数据 Shuffle 算子和多线程同步逻辑,带来资源浪费。
- 默认值已平衡了单查询与并发场景,通常无需用户介入。
- Doris 在持续完善自适应策略,优先在 SQL 级或场景级做必要调整,而非全局。
场景化调参建议
以下示例假设 BE 的 CPU 核数为 16。
场景对照表
| 查询场景 | 推荐并行度 | 原因 |
|---|---|---|
单表点查 / WHERE 少量数据 / LIMIT / 命中物化视图 | 1 | 仅 1 个 Fragment,瓶颈在数据扫描线程(与查询线程独立、自适应并行),查询线程不需多并发。 |
大数据量两表 JOIN / 聚合查询(CPU 密集) | 16 | 计算密集型,CPU 未打满时调大并行度可吃满核心;但不要无限增大(如 48 只会增加调度开销)。 |
| 压力测试场景 | 1 | 并发查询本身已能打满 CPU,过大并行度只会增加线程与框架调度开销。 |
| 复杂查询 | 默认值 | 根据 Profile 与机器负载灵活调整,可按 4 → 2 → 1 阶梯递减观察。 |
场景一:单表简单操作
- 特征:单 Fragment、瓶颈在扫描线程(已自适应并行)。
- 建议:
parallel_pipeline_task_num = 1。 - 理由:扫描线程与查询执行线程相互独立,多并发查询线程无法加速扫描瓶颈。
场景二:大数据量 JOIN/聚合
- 特征:计算密集,观察 CPU 未打满。
- 建议:在默认值基础上调大,例如
parallel_pipeline_task_num = 16。 - 理由:利用 Pipeline 执行引擎的并行能力吃满 CPU;但不应无限制增加,否则线程/框架调度开销反噬性能。
场景三:压力测试
- 特征:并发查询数足够多,CPU 已被多查询打满。
- 建议:
parallel_pipeline_task_num = 1。 - 理由:避免叠加单查询并行度造成的调度开销。
场景四:复杂查询
- 特征:执行计划复杂,瓶颈难以一眼判定。
- 建议:先用默认值,再依据 Profile 与机器负载,按 4 → 2 → 1 阶梯调整观察。
调参方法
Doris 支持三种粒度的并行度设置:SQL 级、会话级、全局级。优先级依次递减。
方法对比
| 方式 | 作用范围 | 适用场景 | 风险 |
|---|---|---|---|
| SQL HINT | 单条 SQL | 针对特定慢 SQL 调优 | 无副作用,最推荐 |
| Session 变量 | 当前会话 | 同会话内一组查询 | 单行查询也会沿用,可能性能下降 |
| Global 变量 | 全集群所有新连接 | 整体 CPU 利用率调整 | 影响范围最大,慎用 |
SQL 级调整
-
目的:用 HINT 精准控制单条 SQL 的并行度,最佳灵活性。
-
命令:
SELECT /*+SET_VAR(parallel_pipeline_task_num=8)*/ *
FROM nation, lineitem
WHERE lineitem.l_suppkey = nation.n_nationkey;
SELECT /*+SET_VAR(parallel_pipeline_task_num=8,runtime_filter_mode=global)*/ *
FROM nation, lineitem
WHERE lineitem.l_suppkey = nation.n_nationkey; -
说明:可在同一 HINT 中叠加其他 session 变量(如
runtime_filter_mode)。
会话级调整
-
目的:让当前会话内的所有 SQL 沿用同一并行度。
-
命令:
SET parallel_pipeline_task_num = 8; -
说明:注意会话内即使是单行点查也会按此并行度执行,可能拖慢轻量查询。
全局调整
-
目的:对所有新连接生效,影响整集群默认行为。
-
命令:
SET GLOBAL parallel_pipeline_task_num = 8; -
说明:仅在确实需要调整全局 CPU 利用率时使用,否则建议留默认值。
FAQ / Troubleshooting
Q1:并行度设大了为什么反而更慢?
过大的并行度会引入更多 Shuffle 与线程同步开销,调度框架本身也有开销。例如 16 核机器设为 48 时几乎没有收益,反而增加调度成本。建议从默认值出发,按 4 → 2 → 1 阶梯调整。
Q2:单表点查为什么并行度建议设为 1?
单表点查只有一个 Fragment,瓶颈在数据扫描。扫描线程与查询执行线程是分开的,扫描线程会自适应并行,因此提升 parallel_pipeline_task_num 不会加速扫描瓶颈。
Q3:压测时为什么也建议并行度为 1?
压测本身有大量并发查询,CPU 已经打满;再叠加单查询并行只会带来线程调度与框架调度的额外开销。
Q4:默认值 0 是什么含义?
parallel_pipeline_task_num = 0 表示由 BE 自动取 CPU 核数的一半。该默认值兼顾了单查询性能与并发吞吐,多数场景无需修改。
Q5:我应该设置全局并行度还是 SQL HINT?
优先使用 SQL HINT 针对个别慢 SQL 调整。仅当确认需要整体调整集群 CPU 利用率时,再使用 SET GLOBAL。
相关参数
| 参数 | 作用 | 默认值 |
|---|---|---|
parallel_pipeline_task_num | 单个 Fragment 在 BE 内的工作任务数 | 0(BE CPU 核数 / 2) |
runtime_filter_mode | Runtime Filter 工作模式,常与并行度联合调优 | 见 Runtime Filter 文档 |