StarRocks执行原理与SQL性能优化策略探索

发布于:2025-04-08 ⋅ 阅读:(38) ⋅ 点赞:(0)

https://zhuanlan.zhihu.com/p/15707561363

聚合优化实践 -- 通过count group by 优化 count distinct数据倾斜问题

除了前面所说的聚合度会对分组聚合造成比较大的影响外,我们还要考虑一个点,即数据倾斜问题。

背景: 如下为最初的用户计算uv的SQL

SELECT 
to_date(dteventtime) AS `日期`
,'所有用户' AS `对比项`
,count(distinct vopenid) AS `总人数`
FROM event AS t1 
WHERE (t1.dteventtime >= '2022-08-18 00:00:00') 
AND (t1.dteventtime <= '2022-08-24 23:59:59') 
AND (   event='xxx')
GROUP BY
 `日期`
 ,`对比项`
ORDER BY
 `日期`
 ,`对比项` LIMIT 50000;

优化

从前面的分析看,整个查询的瓶颈是由于以下两个条件导致的

  1. 分组键数量较少导致了数据倾斜
  2. 上游输出至下游的聚合值为一个大hashSet,导致下游的聚合操作为多个大hashSet的去重操作,这样在数据倾斜的情况下处理效率就严重被拖,且容易造成OOM。

然后我们重新分析uv的计算,本质要做的就是两步:

  1. 按照指定维度对vopenid进行去重
  2. 按照指定维度统计去重后的vopenid数量

这样看就可以对SQL进行一定的改写:

  1. 按照指定维度对vopenid进行去重 :
select to_date(dteventtime) AS `日期`
,vopenid 
FROM event AS t1 
WHERE (t1.dteventtime >= '2022-08-18 00:00:00') 
AND (t1.dteventtime <= '2022-08-24 23:59:59') 
AND ( event='xxx' ) 
group by `日期`,vopenid

首先在阶段1生成的是由 日期+vopenid 的分组键,这样分组数就是(日期数*vopenid数),这样就可以保证每个BE的instance尽可能均匀的分配到数据,大大提高了第二阶段的执行效率。然后第二阶段会收集上游每个instance的分组结果,完成全局的去重操作,并进行第一阶段的分组统计(即按日期统计当前instance数据中日期维度对应的uv)。最后根据日期分桶交由第三阶段计算全局的uv,这里可以看到实际第三阶段还是会存在数据倾斜的情况(即数据最后还是只会由7个instance进行处理),但是这里由于上游为统计后的数据,分组键与聚合值占用空间并不大(只有一个日期和一个统计值),所以不容易造成OOM,而且第三阶段的最终聚合也只要将相同分组的统计结果进行加和即可。假设这里我们有40个BE,每个BE并行度为8,则也只不过是320个加和操作,这比原先的320个大hashSet去重可快多了,所以不会成为整个执行的瓶颈。