max_parallel_workers 必须大于0、max_parallel_degree 必须有效或存在 PARALLEL Hint,否则直接退出parallel_plan_cost_threshold,parallel_query_switch 中 force=on 或存在 PARALLEL Hint 时跳过此检查parallel_scan_records_threshold 时生成)三种分布路径,分片系统中额外生成 hashed(哈希分布)parallel_plan_compare_serial_cost 控制串行路径是否参与比较SELECT * FROM t1 WHERE a > 0 的并行计划:SELECT * FROM t1 JOIN t2:WHERE id BETWEEN X AND Y),优化器可进一步剪枝无关分片max_parallel_degree)WHERE partition_key = X)SELECT /*+ PARALLEL(PARTITION) */ 或 SELECT /*+ PARALLEL(DYNAMIC_RANGE) */模式 | 适用场景 | 说明 |
普通 Gather | 无需保证顺序 | 简单将各 Worker 结果逐行收集并传递给上层算子 |
Merge Sort | 需要 ORDER BY 输出 | 收集时对各 Worker 已排序的结果做归并排序。Worker 端做局部排序,Leader 端做归并 |
parallel_query_switch 中 full_grouping_pushdown 选项已开启(默认开启)SELECT * FROM t1 WHERE t1.dept_id IN (SELECT id FROM departments WHERE region = 'ASIA');
SELECT id FROM departments WHERE region = 'ASIA' 先并行执行,结果共享给扫描 t1 的 Worker。subquery_pushdown 选项开启(默认开启)PQ_INLINE_EVALUATION Hint 可强制此模式。tdsql> EXPLAIN SELECT DISTINCT (COUNT(b) + 1) AS c FROM t1 GROUP BY a;+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------------------+| 1 | SIMPLE | t1 | NULL | ALL | PRIMARY | NULL | NULL | NULL | 43 | 100.00 | Parallel scan (4 workers); Using temporary |+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------------------+tdsql> SHOW WARNINGS;+-------+------+--------------------------------------------------------------------------------------------------+| Level | Code | Message |+-------+------+--------------------------------------------------------------------------------------------------+| Note | 1003 | /* select#1 */ select distinct (count(`b`) + 1) AS `c` from `test`.`t1` group by `test`.`t1`.`a` || Note | 1003 | Query is executed in a parallel plan; explain with tree format to see the plan details. |+-------+------+--------------------------------------------------------------------------------------------------+
Parallel scan (N workers),说明并行生效。同时 WARNING 会提示 "Query is executed in a parallel plan; explain with tree format to see the plan details.",建议使用 tree 格式查看完整并行计划。tdsql> EXPLAIN FORMAT=TREE-> SELECT-> t2.a,-> (SELECT SUM(t1.a) FROM t1) as total_sum,-> (SELECT COUNT(t1.a) FROM t1) as total_count-> FROM t2-> ORDER BY t2.a;+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| EXPLAIN |+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -> Gather (slice: 1, workers: 4) (cost=2310.16..2312.04 rows=5)Merge sort: t2.a-> Sort: t2.a (cost=5.54..5.54 rows=1)-> Table scan on t2, with range parallel scan (cost=2.78..3.48 rows=1)-> Select #2 (subquery in projection; run only once)-> Aggregate: sum(t1.a) (cost=2309.05..2309.05 rows=1)-> Gather (slice: 1, workers: 4) (cost=2308.65..2308.65 rows=1)-> Aggregate: sum(t1.a) (cost=4.14..4.14 rows=1)-> Table scan on t1, with range parallel scan (cost=2.60..3.25 rows=1)-> Select #3 (subquery in projection; run only once)-> Aggregate: count(t1.a) (cost=2306.05..2306.05 rows=1)-> Gather (slice: 1, workers: 4) (cost=2304.43..2305.27 rows=4)-> Count rows in t1 (cost=0.83..0.83 rows=1)Table scan on t1, with pushed projection, with range parallel scan|+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
节点 | 含义 |
Gather (slice: 1, workers: 4) | 4个 Worker 并行执行 Slice 1,Leader 收集结果 |
with range parallel scan 或者 with partition parallel scan | 使用 Dynamic Range Scan/Partition Scan 方式扫描表数据 |
Merge sort: col_name | Gather 收集时做归并排序(保证输出按 col_name 有序) |
Merge sort with duplicate removal: col | Gather 收集时做归并排序并去重 |
Pre-evaluated subqueries: select #N | 预先并行执行完毕的子查询(子查询结果已就绪) |
tdsql> explain analyze verbose select * from t1, t2 where t1.a = t2.a;+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| EXPLAIN |+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -> Inner hash join (t2.a = t1.a) (cost=6.28 rows=3) (actual time=0.511..0.533 rows=3 loops=1)Chunk pair files: 0, memory usage: 16kB-> Table scan on t2 (cost=0.88 rows=3) (actual time=0.167..0.185 rows=3 loops=1)-> Hash-> Table scan on t1 (cost=2.84 rows=3) (actual time=0.262..0.283 rows=3 loops=1)RPC statistics: leader-> LocalScanRecord=latency(ms): 2,0.266323,0.081208...0.185115, retry_count: 0, retry_interval_all(ms): 0.000000, failure_count: 0 |+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
EXPLAIN ANALYZE VERBOSE 适用于需要进一步分析 RPC 开销、内存使用和算子执行细节的场景。SET optimizer_trace_features = 'parallel_plan_optimization=on';SET optimizer_trace = 'enabled=on';EXPLAIN SELECT * FROM t1 WHERE a > 4;SELECT * FROM information_schema.optimizer_trace \\G
considering.chosen: true/false — 是否选择了并行considering.optimization.enumerating_paths — 优化器评估了哪些并行路径cause(未选择并行查询时)— 具体原因,如 plan_cost_less_than_threshold、disabled_by_limit变量名 | 级别 | 默认值 | 说明 |
max_parallel_degree | Session | 4 | 单个查询的最大 Worker 数。设为0禁用并行 |
max_parallel_workers | Global | 10000 | 整个节点的最大 Worker 总数。设为0全局禁用并行 |
变量名 | 级别 | 默认值 | 说明 |
parallel_plan_cost_threshold | Session | 50000 | 串行代价超过该值才考虑生成并行计划 |
parallel_scan_records_threshold | Session | 10000 | 表扫描行数超过该值才将该表纳入并行扫描候选 |
parallel_scan_ranges_threshold | Session | 2 | 可切分的扫描范围数超过该值才使用并行计划 |
变量名 | 级别 | 默认值 | 说明 |
parallel_query_switch | Session | 见说明 | 并行查询功能开关,位掩码格式,支持多个选项同时设置 |
parallel_query_switch 选项说明:选项 | 默认 | 说明 |
force | off | 强制使用并行计划,跳过所有 cost 和行数阈值检查 |
subquery_pushdown | on | 支持相关子查询整体推送到 Worker 上并行执行 |
full_grouping_pushdown | on | 当 Worker 间 GROUP BY 键值不重复时,将聚合完全下推到 Worker |
group_min_max_pushdown、partition_group_min_max_pushdown、dynamic_range_parallel_scan、partition_parallel_scan 等扫描方式选项,默认均开启。parallel_query_switch 是一个开发者选项,用于调试。每个发布都可能调整开关的内容(包括添加或删除),请勿在管理工具或正规的维护脚本中使用。-- 查看当前开关值SHOW VARIABLES LIKE 'parallel_query_switch';-- 强制并行(跳过所有阈值检查)SET parallel_query_switch = 'force=on';-- 关闭子查询下推(含相关子查询的查询不走并行)SET parallel_query_switch = 'subquery_pushdown=off';
限制项 | 说明 |
Dynamic Range Scan | 只能在 Leader 上执行 |
Index Merge 扫描 | 不支持并行扫描 |
Rollup | 不包含 |
SELECT 列表中相关子查询 | 不支持(如 SELECT 列表中引用了外层查询的列) |
非 Parallel Safe 表达式 | 如用户变量 @a:=1 等不支持并行 |
parallel_query_switch='force=on' 跳过所有检查):max_parallel_degree > 0parallel_plan_cost_thresholdmax_parallel_degree 是否为0plan_cost_less_than_threshold → 降低 parallel_plan_cost_thresholdSET parallel_query_switch='force=on' 强制并行max_parallel_degreeCALL dbms_admin.statement_outline_add_rule('rule_name','SELECT /*+ PARALLEL(4) */ SUM(c), b FROM t1 GROUP BY b');
PARALLEL(PARTITION) 按分区扫描PARALLEL(DYNAMIC_RANGE) 按范围扫描文档反馈