SQL并行查询优化实践:从执行计划看并行能力的正确使用

前言

随着业务数据规模不断增长,单条SQL的执行时间逐渐成为影响系统性能的重要因素。在多核CPU已经成为服务器标配的今天,如何充分利用硬件资源提升查询效率,是数据库优化过程中经常面对的问题。

KingbaseES提供了完善的并行查询能力,可以将一个大型查询拆分为多个任务,由多个Worker协同完成,从而降低单个CPU核心的计算压力,缩短SQL执行时间。

但在实际工作中,经常会遇到这样的情况:

明明表中已经有数百万甚至上千万数据,CPU资源也比较充足,执行计划却依然选择单线程执行;甚至添加了并行Hint之后,SQL仍然没有走并行计划。

本文结合实际案例,对KingbaseES中的并行机制进行分析,并介绍影响并行执行计划生成的几个关键因素。


一个简单的并行案例

构造1000万行测试数据:

sql 复制代码
CREATE TABLE app_family2(
    family_id varchar(32),
    application_id varchar(32),
    family_number varchar(50),
    household_register_number varchar(50),
    poverty_reason varchar(32)
);

INSERT INTO app_family2
SELECT generate_series(1,10000000),
       generate_series(1,10000000),
       'aaaa',
       'aaa',
       'bbb';

查询全部数据:

sql 复制代码
EXPLAIN ANALYZE
SELECT * FROM app_family2;

执行计划如下:

text 复制代码
Gather
  Workers Planned: 2
  Workers Launched: 2
  -> Parallel Seq Scan

可以看到数据库启动了两个并行Worker参与扫描,每个Worker负责部分数据读取工作,最终由Gather节点汇总结果。

这种执行方式能够有效利用多核CPU资源,在大表扫描场景下通常能够获得较好的性能收益。


为什么有些SQL无法走并行

很多用户会发现,同样的数据量下,有些SQL能够使用并行,而有些SQL始终是单线程执行。

例如:

sql 复制代码
INSERT INTO testu
SELECT COUNT(*)
FROM test;

查看执行计划:

text 复制代码
Insert on testu
  -> Aggregate
       -> Seq Scan on test

整个执行过程只有一个Seq Scan,没有出现Gather和Parallel Seq Scan节点。

即使开启:

sql 复制代码
SET force_parallel_mode=on;

执行计划仍然不会发生变化。

这是因为当前版本中,INSERT INTO ... SELECT语句不会生成并行查询计划。

对于需要利用并行能力完成数据装载的场景,可以采用以下方式改写SQL:

sql 复制代码
SELECT COUNT(*)
INTO testu
FROM test;

或者:

sql 复制代码
CREATE TABLE testu AS
SELECT COUNT(*)
FROM test;

改写后执行计划中即可看到:

text 复制代码
Gather
  Workers Planned: 2
  -> Parallel Seq Scan

实现并行计算。


并行度并不是越大越好

很多DBA在看到并行功能后,第一反应是提高Worker数量。

例如:

sql 复制代码
SET max_parallel_workers_per_gather=4;

再次执行查询:

text 复制代码
Workers Planned: 4
Workers Launched: 4

数据库会启动4个Worker参与计算。

但需要注意的是,并行度增加并不意味着性能一定提升。

随着Worker数量增加,会产生:

  • 任务分发开销
  • 结果汇总开销
  • 进程调度开销

当数据量较小或者CPU资源紧张时,过高的并行度反而可能导致性能下降。

因此并行度设置需要结合:

  • CPU核心数量
  • 数据规模
  • 系统负载

综合评估,而不是简单地无限增大。


优化器为什么放弃并行

实际生产环境中,更常见的问题是:

数据库明明支持并行,却没有选择并行执行。

原因通常来自优化器成本评估。

KingbaseES在生成执行计划时,会比较:

text 复制代码
串行执行成本
VS
并行执行成本

如果优化器认为:

text 复制代码
并行收益 < 并行开销

则不会生成并行计划。

其中影响较大的参数是:

sql 复制代码
parallel_tuple_cost
parallel_setup_cost

例如:

sql 复制代码
SET parallel_tuple_cost=0.001;

重新查看执行计划:

text 复制代码
Gather
  Workers Planned: 2
  -> Parallel Seq Scan

此时优化器会更倾向于采用并行方案。

因此,在一些大表扫描场景下,如果发现执行计划始终无法并行,可以适当调整相关成本参数进行验证。


自定义函数导致并行失效

除了参数因素外,自定义函数也是影响并行执行的重要原因。

例如:

sql 复制代码
SELECT
    family_id,
    fun_getdistance1(
        family_id::numeric,
        application_id::numeric
    )
FROM app_family2;

即使增加Parallel Hint,执行计划仍然可能是单线程。

原因在于函数默认并不一定支持并行执行。

可以通过以下方式查看函数属性:

sql 复制代码
SELECT *
FROM sys_proc
WHERE proname='fun_getdistance1';

如果函数被标记为:

text 复制代码
PARALLEL UNSAFE

则无法参与并行执行。

修改方式:

sql 复制代码
ALTER FUNCTION fun_getdistance1
PARALLEL SAFE;

修改后优化器才会考虑生成并行计划。


CTE场景下的并行限制

另一个容易忽略的问题是WITH语句。

例如:

sql 复制代码
WITH a AS (
    SELECT *
    FROM app_family
)
SELECT *
FROM a;

执行计划通常为:

text 复制代码
Seq Scan on app_family

不会出现并行扫描节点。

因此在需要极致性能的场景下,应关注CTE对执行计划的影响,必要时考虑改写SQL结构。


总结

并行查询本质上是利用多核CPU资源换取更短的SQL执行时间,但并不是所有SQL都能够自动获得并行能力。

从实际案例来看,影响并行执行的因素主要包括:

  • SQL类型是否支持并行
  • Worker数量配置
  • 优化器成本评估参数
  • 自定义函数并行属性
  • CTE等特殊SQL结构

在日常性能优化过程中,建议首先通过执行计划确认SQL是否真正进入并行模式,再结合业务特点调整并行参数,而不是单纯依赖Hint或者提高并行度。只有理解优化器的决策逻辑,才能真正发挥并行查询的性能优势。

相关推荐
IvorySQL2 小时前
PostgreSQL 技术日报 (6月7日)|峰会线上通道开放
数据库·postgresql
Ze3G90nYt2 小时前
Redis 分布式锁进阶第一百二十篇
数据库·redis·分布式
华山令狐虫2 小时前
DBAPI 接入 Milvus 向量数据库:HTTP 执行器参数映射实战
数据库·http·milvus·dbapi
Fuly10242 小时前
LangGraph学习-(1)跑通一个最小状态图
数据库·学习
计算机安禾2 小时前
【数据库系统原理】第5篇:关系的完整性约束:实体、参照与用户定义的逻辑守卫
数据库·oracle
snow@li2 小时前
数据库:Schema = 数据库的“蓝图“或“命名空间“
数据库
如竟没有火炬2 小时前
恢复二叉搜索树
数据结构·数据库·python·leetcode·动态规划
星川皆无恙2 小时前
基于BERT+LSTM+CRF与知识图谱的医疗智能问答系统实战:Neo4j图数据库+实体识别+意图分析完整项目
数据库·人工智能·深度学习·bert·lstm·知识图谱·neo4j
持敬chijing2 小时前
Web渗透之SQL注入-URL解码注入(URL Decode Injection)
sql·安全·web安全·网络安全·网络攻击模型·安全威胁分析