GBase 8c 分析查询一开并行就变慢,我排查时先看这几处
GBase 8c 分析查询一开并行就变慢,我排查时先看这几处
我最近整理 GBase 8c 相关资料时,一个感受特别明显:现场里很多“分析 SQL 跑得慢”的问题,并不是简单把 query_dop 调大就能解决。真正落到排查现场,常见情况往往是这几层一起叠着出问题:单条 SQL 内存不够、并发队列把系统压住、并行场景选错、LLVM 额外编译开销不合适、重查询和在线业务没有做隔离。
我自己现在碰到这类问题,基本不会先问“并行开到几”,而是先问三个更实际的问题:
- 这条 SQL 是不是已经在落盘了。
- 系统是不是已经被并发作业挤满了。
- 这条 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_memory、shared_buffers、cstore_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_mem、query_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
我现在更习惯的一套处理顺序
真到现场时,我一般按下面这个顺序走,不太会乱:
- 先看执行计划
能跑完就上EXPLAIN PERFORMANCE,跑不完先EXPLAIN。 - 再看有没有落盘
重点看work_mem、max_process_memory、pg_total_memory_detail()、pgxc_total_memory_detail()。 - 然后判断是不是并发过载
看max_active_statements、会话数、业务类型是不是混在一起。 - 再做会话级并行试探
用query_dop做 A/B,对比收益,不直接全局改。 - 最后再碰 LLVM 和资源池
单条 SQL 优化解决不了的,再考虑enable_codegen、codegen_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
评论
热门帖子
- 12025-12-01浏览数:182759
- 22023-05-09浏览数:25051
- 42023-09-25浏览数:18521
- 52020-05-11浏览数:17526