GBase 8c
性能调优
文章

GBase 8c 分析查询一开并行就变慢,我排查时先看这几处

发表于2026-04-01 10:39:2111次浏览3个评论

GBase 8c 分析查询一开并行就变慢,我排查时先看这几处

我最近整理 GBase 8c 相关资料时,一个感受特别明显:现场里很多“分析 SQL 跑得慢”的问题,并不是简单把 query_dop 调大就能解决。真正落到排查现场,常见情况往往是这几层一起叠着出问题:单条 SQL 内存不够、并发队列把系统压住、并行场景选错、LLVM 额外编译开销不合适、重查询和在线业务没有做隔离。

我自己现在碰到这类问题,基本不会先问“并行开到几”,而是先问三个更实际的问题:

  1. 这条 SQL 是不是已经在落盘了。
  2. 系统是不是已经被并发作业挤满了。
  3. 这条 SQL 到底适不适合并行和 LLVM。

先别急着调参数,我一般先把现象分成这几类

现场现象我优先怀疑的点第一动作
CPU 没打满,但 SQL 很慢work_mem 偏小、算子落盘看执行计划和内存视图
并发一上来整体都慢max_active_statements、资源池隔离不足先看是不是队列排队
单条大查询开并行后更慢query_dop 场景不对看计划里是不是适合 SMP
小结果集 SQL 开启优化后更慢enable_codegen / codegen_cost_threshold 不合适做一次会话级 A/B 对比
ETL、报表和联机业务互相抢资源资源池、Cgroups 没隔离单独拆资源组

这个表不是死规则,但从落地角度看,先这么拆,定位速度会快很多。

一、先看是不是内存不够,算子已经开始落盘

我自己理解下来,GBase 8c 里最容易被忽略的不是并行,而是内存。work_mem 不够时,Sort、Hash、Agg 这类算子会把数据写到临时表空间,性能通常会明显下降。另一方面,节点上执行作业真正能用的内存,也会同时受到 max_process_memoryshared_bufferscstore_buffers 这些配置的影响。

我现场里一般先跑这几条:

show max_process_memory;
show shared_buffers;
show cstore_buffers;
show work_mem;

select * from pg_total_memory_detail();
select * from pgxc_total_memory_detail();

如果是单条复杂查询很慢,我更愿意先做一次会话级试探,而不是直接改全局参数:

set work_mem = '512MB';

explain performance
select c.cust_id,
       sum(o.order_amount) as total_amt
from   sales.order_fact o
join   sales.customer_dim c
       on o.cust_id = c.cust_id
where  o.order_date >= date '2026-03-01'
and    o.order_date <  date '2026-04-01'
group by c.cust_id;

我自己更常盯的几个参数

参数我关注它的原因适合优先看的场景
max_process_memory决定节点逻辑内存峰值上限节点整体内存紧张
shared_buffers会影响执行作业剩余可用内存缓存较大、执行内存被挤压
cstore_buffers列存缓冲也会占用内存预算列存分析场景
work_mem直接影响 Sort/Hash/Agg 是否落盘单条复杂 SQL 慢

这里我个人比较在意一点:work_mem 不是越大越好。单条 SQL 变快,不代表系统整体就稳。真正落到生产上,还是得把“单查询时延”和“总并发吞吐”一起算。

二、再看是不是并发队列已经把系统压住了

很多同学看到慢查询,第一反应是“这条 SQL 不够快”;但我这边更常见的情况是,这条 SQL 本身不一定最差,而是系统里同时跑的大活太多,大家一起排队。

我通常会先看:

show max_active_statements;
show parctl_min_cost;
select count(*) from pg_stat_activity;

然后把业务场景先归一类,不同场景思路差很多:

场景我更倾向的做法
高并发事务型不先用 max_active_statements 去强卡,先稳吞吐
低并发分析型控制全局并发,避免一批大 SQL 同时把内存和 I/O 打穿
混合负载用资源池把报表、批处理、在线业务拆开
临时跑数窗口会话级提参数,跑完立即回收

这个点我踩过几次坑以后,基本就不太相信“所有慢 SQL 都靠单条优化解决”这件事了。很多时候不是 SQL 不行,而是系统已经没有余粮了。

三、并行不是常开开关,先判断这条 SQL 适不适合 SMP

GBase 8c 的 SMP 更适合分析型查询:单条 SQL 耗时长、并发度低、系统资源还有富余。

我一般这样试:

set query_dop = 1;
explain performance
select ...
;

set query_dop = 4;
explain performance
select ...
;

reset query_dop;

我更习惯把“有没有收益”分成下面这张表来看:

更适合开并行不太适合开并行
单条耗时长的分析 SQL高并发 OLTP 短 SQL
顺序扫描、大范围聚合、Hash Join索引扫描为主的 SQL
资源利用率还比较低CPU / I/O 已经偏高
低并发、批量报表、离线跑数存储过程内的细碎查询

我自己的经验是,query_dop 最适合做“会话级手术刀”,不适合做“全库常驻开关”。

四、LLVM 不是所有 SQL 都值得开足

这个点也很容易被忽略。复杂表达式、大数据量、向量化执行场景更容易吃到 LLVM 的收益;但如果是小数据量、SQL 本身很短,或者内存不够导致中途频繁下盘,LLVM 的收益就不一定能覆盖它的编译成本。

我一般会这么做一次 A/B:

show enable_codegen;
show codegen_cost_threshold;

set enable_codegen = off;
explain performance
select ...
;

set enable_codegen = on;
set codegen_cost_threshold = 20000;
explain performance
select ...
;

reset enable_codegen;
reset codegen_cost_threshold;

这个点我自己的判断比较简单

现象我的处理倾向
小 SQL、本来就很快不急着碰 LLVM
大表达式、大聚合、大 Join可以保留 LLVM,重点看收益
开启后反而慢提高 codegen_cost_threshold 或会话级关闭
同时还有落盘先解决 work_mem,再谈 LLVM

很多人会把“并行”和“编译优化”混成一个按钮去理解,但我自己更倾向于把它们拆开:一个是多线程换时间,一个是编译换执行效率,问题根子不一样。

五、混合负载下,最好把重查询和在线业务隔开

如果系统里同时跑 ETL、报表和在线查询,只靠 work_memquery_dop 这些参数去兜,通常不太稳。真正落地时,我更建议把资源管理单独拉出来看,尤其是重报表、批处理、在线接口不要都堆在默认资源组里。

下面这段我更愿意当成“思路示意”来看:

# 在每个相关节点上执行
gs_cgroup -c -S report_class -G report_wd -E "blocktime=60,elapsedtime=1800,spillsize=10240"

# 日常看实例状态
gha_ctl monitor all -H -l http://10.90.14.21:2379

我现在更习惯的一套处理顺序

真到现场时,我一般按下面这个顺序走,不太会乱:

  1. 先看执行计划
    能跑完就上 EXPLAIN PERFORMANCE,跑不完先 EXPLAIN
  2. 再看有没有落盘
    重点看 work_memmax_process_memorypg_total_memory_detail()pgxc_total_memory_detail()
  3. 然后判断是不是并发过载
    max_active_statements、会话数、业务类型是不是混在一起。
  4. 再做会话级并行试探
    query_dop 做 A/B,对比收益,不直接全局改。
  5. 最后再碰 LLVM 和资源池
    单条 SQL 优化解决不了的,再考虑 enable_codegencodegen_cost_threshold、资源池/Cgroups 隔离。

几个我自己比较容易提醒团队的坑

  • 别把 work_mem 当成“单机剩余内存的一次性分配”
    它是会被并发放大的,单条查询看起来很美,系统并发上来就容易失控。
  • 别把 query_dop 当成通用提速器
    场景不对时,它会把 CPU、I/O、内存一起抬上去,最后整体更慢。
  • 别忽略 max_active_statements 的业务差异
    分析系统和事务系统调法不一样,这个参数不是越小越稳,也不是越大越好。
  • 别把混合负载都扔在默认资源组里
    真正落地时,重报表、批处理、在线接口不隔离,最后通常谁都不满意。

收个尾

我最近重新整理 GBase 8c 这块内容时,越来越觉得“分析查询慢”这件事,核心不在某个单点参数,而在有没有把执行内存、全局并发、并行适配、LLVM 成本和资源隔离这几层连起来看。很多时候,大家盯着 query_dop 不放,反而会把真正的问题绕过去。

从落地角度看,我个人更倾向于这么理解:
先确认是不是落盘,再确认是不是排队,再确认这条 SQL 适不适合并行,最后才是做更细的编译优化和资源池隔离。
这个顺序不一定最“炫”,但我觉得更接近现场,也更容易把问题处理稳。

参考资料

[1] 南大通用GBase 8c系统调优参考指南
https://www.gbase.cn/community/post/4766

[2] GBase 8c执行计划性能调优
https://www.gbase.cn/community/post/3966

[3] 资源负载管理
https://www.gbase.cn/docs/gbase-8c/03%20%E5%BC%80%E5%8F%91%E8%80%85%E6%8C%87%E5%8D%97/%E8%B5%84%E6%BA%90%E8%B4%9F%E8%BD%BD%E7%AE%A1%E7%90%86

[4] gs_cgroup工具说明
https://www.gbase.cn/community/post/3009

[5] 例行维护
https://www.gbase.cn/docs/gbase-8c/02%20%E7%AE%A1%E7%90%86%E5%91%98%E6%8C%87%E5%8D%97/03%20%E8%BF%90%E7%BB%B4%E7%AE%A1%E7%90%86/%E4%BE%8B%E8%A1%8C%E7%BB%B4%E6%8A%A4

评论

登录后才可以发表评论
用户头像
山佳发表于 4个月前
1111
青菇凉发表于 2个月前
闪闪发光
GBase用户47954发表于 1个月前
感谢作者的精彩分享!