《SQL优化核心思想 (罗炳森 黄超 钟侥)》

一、场景描述
在做数据汇总计算和统计分析时,最头疼的就是去重类指标计算(比如用户数、商家数等),特别是还要带多种维度的下钻分析,由于其不可累加的特性,几乎每一项换一个统计维度组合,都得重新计算。数据量小时考虑可以自动化的用明细数据即时直接统计,但当数据量大时就不得不提前进行计算了。

获取PDF访问它↓
python33
它↑是个网址,加上后缀即可。

典型场景如下:省、市、区等维度下的支付宝客户端的日支付用户数(其中省、市、区为用户支付时所在的位置,表格中数据指标对应的)。

存在一种情况,某用户早上在杭州市使用支付宝支付了一次,下午跑到绍兴市时又使用支付宝线下支付了一次。那么在统计省+市维度的日支付用户数时,需要为杭州市、绍兴市市各维度下,需要按用户去重,只能为浙江省维度1。针对这种情况,通常就需要以Cube的方式完成数据预计算,同时每个维度组合都需要进行去重操作,因为不可累加。本文中的场景大致为去重立方。

二、常见的实现方法
直接计算,每个维度组合单独计算。比如单独生成省、省+市、省+市+区等维度组合的多张表。每个表只计算固定的维度。然后是数据膨胀再计算,如并集All或者Lateral View Explode或者MaxCompute的Cube计算功能,通过数据膨胀实现一个数据满足多种维度组合的数据计算方法,如下图所示。

这个第三写法其实都类似,重点都在于如图所示对数据进行膨胀,再进行重统计。其执行流程如下图,核心思路去都是先把数据“膨胀”拆为多行,再按照“普通”的Distinct去重统计,因此性能上本身无严重差异,主要在于代码可维护性上。

三、性能分析
接下来方法核心都是先把数据“膨胀”拆为多行,再按照“普通”的不同去重统计,本身性能无差异,主要在于代码可维护性上。这几种方案计算耗时会随着需求维度组合线性增加,同时还要加上独特的本身对计算性能差的影响。

在实际实验中,我们发现,去重立方的计算过程中,80%+的计算成本消耗在数据膨胀和数据传输上。比如提取核心指标场景,需要计算各种组合维度下支付的用户数来实际实验中,大量100亿数据x25种维度组合进行测试,实际执行支撑任务如下图所示,其中R3_2为核心的数据膨胀过程,数据膨胀近10倍,中间结果数据大小由100GB膨胀至1TB 、数据量由100亿膨胀至近1300亿,大部分计算资源和计算运行时间都花在数据膨胀和传输上。若实际的组合维度进一步增加的话,数据膨胀大小也将进一步增加。

四、一个新思路
首先对问题进行拆解下,去重立方体的计算过程核心分为两个部分,数据膨胀+数据去重。数据膨胀解决的是一行数据同时满足多个维度组合的计算,数据去重块完成最终的去重统计,核心解决方案还是源于原始数据去匹配结果数据的需要。其中数据去重本身的计算量就会增大,而数据膨胀会导致这种情况加剧,因为计算过程中需要解拆和在shuffle过程中传输大量的数据。数据计算过程中是先膨胀再聚合,加上本身数据内容的中英文字符串内容增大,所以才导致大量的数据计算和传输成本。

而我们的核心思想是能够避免数据膨胀,同时进一步减少数据传输大小。因此我们联想到,是否可以采用类似用户打标签的数据打标方案,先进行数据去重生成UID粒度的中间数据,同时让需要的结果维度组合反向附加到UID粒度的数据上,这个过程中记录结果维度进行数量,用更小的数据结构去存储,避免数据计算过程中的大量数据传输。整个数据计算过程中,数据量理论上是逐渐收敛的,不会因为统计维度组合的增加而增加。

4.1.核心思想


核心计算思路如上图,普通的数据膨胀计算立方体的方法,中间需要对数据进行膨胀,再聚合,其中结果统计需要的组合维度数就是数据膨胀的倍数,就像上面的“省、省+市”总共两个维度组合,数据预计要膨胀2倍。

而新的数据聚合方法,通过一定的策略方法将维度组合拆解为维度小表并进行编号,然后将哪些订单明确细数据聚合至用户粒度的中间流程数据,其中各类组合维度转换为数字标签记录到用户维度的数据记录上,整个计算过程数据量是呈收缩聚合的,不会膨胀。

4.2.逻辑实现
明细数据准备:以用户线下支付数据为例,明细记录包含订单编号、用户ID、支付日期、所在省份、最终所在市、支付金额。指标统计需求为统计包含省份、市组合维度+支付用户数的多维立方体。
订单编号    用户ID    支付日期    所在省    所在市    支付金额
2023111101    U001    2023-11-11    浙江省    杭州市    1.11
2023111102    U001    2023-11-11    浙江省    绍兴市    2.22
2023111103    U002    2023-11-11    浙江省    杭州市    3.33
2023111104    U003    2023-11-11    江苏省    南京市    4.44
2023111105    U003    2023-11-11    浙江省    温州市    5.55
2023111106    U004    2023-11-11    江苏省    南京市    6.66
整体方案流程如下图。

STEP1:对明细数据进行所需的要素提取(即Group By对应字段​​),得到维度集合。


STEP2:对得到的维度集合生成Cube,物质Cube的行进行编码(假设需要所在省、所在省+所在市2种组合维度),可以用ODPS的Cube功能实现,再根据生成的Cube维度组合进行排序生成唯一编码。
原始维度:所在省    原始维度:所在省    Cube 维度:所在省    Cube 维度:所在市    Cube行ID(可通过排序生成)
浙江省    杭州市    浙江省    全部    1
浙江省    杭州市    浙江省    杭州市    2
浙江省    绍兴市    浙江省    全部    1
浙江省    绍兴市    浙江省    绍兴市    3
浙江省    温州市    浙江省    全部    1
浙江省    温州市    浙江省    温州市    4
江苏省    南京市    江苏省    全部    5
江苏省    南京市    江苏省    南京市    6
STEP3:将Cube的行编码,根据映射关系回写到用户明细上,可用Mapjoin的方式实现。
订单编号    用户ID    支付日期    所在省    所在市    汇总的Cube ID
2023111101    U001    2023-11-11    浙江省    杭州市    [1,2]
2023111102    U001    2023-11-11    浙江省    绍兴市    [1,3]
2023111103    U002    2023-11-11    浙江省    杭州市    [1,2]
2023111104    U003    2023-11-11    江苏省    南京市    [5,6]
2023111105    U003    2023-11-11    浙江省    温州市    [1,4]
2023111106    U004    2023-11-11    江苏省    南京市    [5,6]
STEP4:汇总到用户维度,可视化Cube ID集合字段进行去重(可以用ARRAY的DISTINCT)


STEP5:按照Cube ID进行计数计算(由于STEP4已经去重啦,因此这里不需要再进行去重);然后按照映射关系进行维度还原。
立方体ID    下单用户数指标    Cube 还原维度:所在省    Cube 还原维度:所在市
1    3    浙江省    全部
2    2    浙江省    杭州市
3    1    浙江省    绍兴市
4    1    浙江省    温州市
5    2    江苏省    全部
6    2    江苏省    江苏省
结束~

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值