count distinct在spark中的运行机制

文章目录

预备 数据和执行语句

sql 复制代码
SELECT 
  COUNT(*), 
  SUM(items), 
  COUNT(DISTINCT product), 
  COUNT(DISTINCT category) 
FROM orders;

假设源数据分布在两个1核的结点上,数据就8行

Expand

spark把count distinct操作转换成count操作。

第一步是对每个要count distinct的列,生成新的行(这里是product和category列),当然原来不需要distinct聚合的列也在。

原来items列不需要distinct,product和category列要distinct,所以数据膨胀了2倍。原来8条数据,现在是8*(1+2)=24条

spark加了gid这一列,值为0代表所有非distinct聚合(这里是count(*)和sum(items)),值为1和2分别代表其他distinct聚合(这里1代表product,2代表category)。

NULL是怎么赋值的:对输入列来说,每行只有1个非空值。在spark的物理执行计划中,可以看到操作是这样的

复制代码
  Expand
    Input: [product, category, items]
    Arguments: [
      [null, null, 0, items],
      [product, null, 1, null],
      [null, category, 2, null]]

第一次HashAggregate

Spark使用所有count distinct的列和gid作为关键字(product、category和gid)对行进行局部散列,并对非distinct的聚合(count(*)和SUM(items))执行局部局部聚合:

相当于执行了select product,category,gid,count(*) cnt,sum(items) items from 膨胀后的表 group by product,category,gid

这可以使得膨胀后的数据变小。

如果不同值的数量比较少,减少的数据是相当可观的,最终结果可能比原始数据还要少。

可以看到原来每个结点上有4行,膨胀后是12行,局部聚合后变成了6行。

Shuffle and Second HashAggregate

在每个结点内部HashAggregate后,经过shuffle后变成这样

重新再每个结点做局部shuffle,得到

(相当于执行了select product,category,gid,count(*) cnt,sum(items) items from 膨胀后的表 group by product,category,gid

这一步使得所有键都变成了唯一的。

最后结果

现在所有行可以合并成一个partition,再次HashAggregation,但这次不用group by product, category和gid

现在再也没有重复值了,简单的count和根据gid筛选就可以得到想要的count distinct结果

复制代码
  cnt FILTER (WHERE gid = 0),
  sum FILTER (WHERE gid = 0),
  COUNT(product) FILTER (WHERE gid = 1),
  COUNT(category) FILTER (WHERE gid = 2)

Result:

复制代码
  COUNT(*):                  8
  SUM(items):              120
  COUNT(DISTINCT product):   4
  COUNT(DISTINCT category):  2

性能

  • 如果不同值的数量比较少,那么即使膨胀后,最后要shuffle的行也很少,这样因为spark局部聚合的原因,count distinct是相对比较快的
  • 如果不同值的数量很多,并且你在一个语句中使用多个count distinct对不同的列。那么要shuffle行因为膨胀会很多,局部聚合也不能有效遏制数据的膨胀,那么要让查询语句成功执行需要消耗更多的executor内存。

原文

Distributed COUNT DISTINCT -- How it Works in Spark, Multiple COUNT DISTINCT, Transform to COUNT with Expand, Exploded Shuffle, Partial Aggregations -- Large-Scale Data Engineering in Cloud (cloudsqale.com)

相关推荐
得物技术13 小时前
深入剖析Spark UI界面:参数与界面详解|得物技术
大数据·后端·spark
武子康15 小时前
大数据-238 离线数仓 - 广告业务 Hive分析实战:ADS 点击率、购买率与 Top100 排名避坑
大数据·后端·apache hive
武子康2 天前
大数据-237 离线数仓 - Hive 广告业务实战:ODS→DWD 事件解析、广告明细与转化分析落地
大数据·后端·apache hive
大大大大晴天2 天前
Flink生产问题排障-Kryo serializer scala extensions are not available
大数据·flink
武子康4 天前
大数据-236 离线数仓 - 会员指标验证、DataX 导出与广告业务 ODS/DWD/ADS 全流程
大数据·后端·apache hive
肌肉娃子4 天前
20260227.spark.Spark 性能刺客:千万别在 for 循环里写 withColumn
spark
武子康5 天前
大数据-235 离线数仓 - 实战:Flume+HDFS+Hive 搭建 ODS/DWD/DWS/ADS 会员分析链路
大数据·后端·apache hive
DianSan_ERP5 天前
电商API接口全链路监控:构建坚不可摧的线上运维防线
大数据·运维·网络·人工智能·git·servlet
够快云库5 天前
能源行业非结构化数据治理实战:从数据沼泽到智能资产
大数据·人工智能·机器学习·企业文件安全
AI周红伟5 天前
周红伟:智能体全栈构建实操:OpenClaw部署+Agent Skills+Seedance+RAG从入门到实战
大数据·人工智能·大模型·智能体