前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SparkSql不同写法的一些坑(性能优化)

SparkSql不同写法的一些坑(性能优化)

作者头像
数据仓库践行者
发布2022-11-25 19:58:03
7411
发布2022-11-25 19:58:03
举报

说三种情况,看大家有没有遇到类似的场景。

第一种情况:

这种情况也是我经常会遇到的一个场景,之前也有同学拿着sql来问,说这样写会不会影响运行效率:

代码语言:javascript
复制
select  
  tmp.A 
from (select A,B from testdata2) tmp

结论是

不用担心,这样写完全可以被优化

代码语言:javascript
复制
== Analyzed Logical Plan ==
Project [A#3]
+- SubqueryAlias tmp
   +- Project [A#3, B#4]
      +- SubqueryAlias testdata2
         +- View (`testData2`, [a#3,b#4])
            +- SerializeFromObject [knownnotnull(assertnotnull(input[0, org.apache.spark.sql.test.SQLTestData$TestData2, true])).a AS a#3, knownnotnull(assertnotnull(input[0, org.apache.spark.sql.test.SQLTestData$TestData2, true])).b AS b#4]
               +- ExternalRDD [obj#2]  
                         
== Optimized Logical Plan ==
Project [A#3]
+- SerializeFromObject [knownnotnull(assertnotnull(input[0, org.apache.spark.sql.test.SQLTestData$TestData2, true])).a AS a#3]
   +- ExternalRDD [obj#2]

从执行计划上清晰的看到,最终被优化成

代码语言:javascript
复制
select A from testdata2

这样的效果,主要是 ColumnPruning(列裁剪) 和 CollapseProject(合并Project)这两种优化器起到作用。

第二种情况:

这种情况之前一直没在意,发现我写过的一些代码里默默都这么用了

代码语言:javascript
复制
 -- 其中myudf是一个自定义UDF函数,返回一个数组
 select 
   myudf(A,B)[0] as a1,
   myudf(A,B)[1] as a2,
   myudf(A,B)[2] as a3 
 from testdata2
 

这里myudf(A,B)执行几遍?

结论是

会执行三遍。

如果myudf是一个很复杂的函数,要合并两个非常复杂的字符串A和B,这个也是我工作中的一个场景。这样的话,执行三遍,非常不合理。

怎么办?

改写:

代码语言:javascript
复制
 -- 其中myudf是一个自定义UDF函数,返回一个数组
 select 
   atmp[0] as a1,
   atmp[1] as a2,
   atmp[2] as a3 
 from 
 (select 
   myudf(A,B) as atmp
 from testdata2
 ) tmp

这样改写就万事大吉了嘛?

在sparksql branch3.3 这样改写完全没问题,但毕竟3.3是新版本,大部分人都还没用上,换到3.3之前的版本,分分钟再给变(优化)成第一种写法(执行三遍的)。

branch3.3(是ok的,内层先计算出myudf的值,外层用计算过的值取数):

代码语言:javascript
复制
== Analyzed Logical Plan ==
Project [atmp#10[0] AS a1#11, atmp#10[1] AS a2#12, atmp#10[2] AS a3#13]
+- SubqueryAlias tmp
   +- Project [myudf(A#3,B#4) AS atmp#10]
      +- SubqueryAlias testdata2
         +- View (`testData2`, [a#3,b#4])
            +- SerializeFromObject [knownnotnull(assertnotnull(input[0, org.apache.spark.sql.test.SQLTestData$TestData2, true])).a AS a#3, knownnotnull(assertnotnull(input[0, org.apache.spark.sql.test.SQLTestData$TestData2, true])).b AS b#4]
               +- ExternalRDD [obj#2]



== Optimized Logical Plan ==
Project [atmp#10[0] AS a1#11, atmp#10[1] AS a2#12, atmp#10[2] AS a3#13]
+- Project [myudf(A#3,B#4) AS atmp#10]
   +- SerializeFromObject [knownnotnull(assertnotnull(input[0, org.apache.spark.sql.test.SQLTestData$TestData2, true])).a AS a#3, knownnotnull(assertnotnull(input[0, org.apache.spark.sql.test.SQLTestData$TestData2, true])).b AS b#4]
      +- ExternalRDD [obj#2]

branch3.3之前的版本(不管我们愿不愿意,都给合并喽):

代码语言:javascript
复制
== Analyzed Logical Plan ==
Project [atmp#10[0] AS a1#11, atmp#10[1] AS a2#12, atmp#10[2] AS a3#13]
+- SubqueryAlias tmp
   +- Project [concat(array(A#3), array(B#4)) AS atmp#10]
      +- SubqueryAlias testdata2
         +- SerializeFromObject [knownnotnull(assertnotnull(input[0, org.apache.spark.sql.test.SQLTestData$TestData2, true])).a AS a#3, knownnotnull(assertnotnull(input[0, org.apache.spark.sql.test.SQLTestData$TestData2, true])).b AS b#4]
            +- ExternalRDD [obj#2]
            
== Optimized Logical Plan ==            
Project [myudf(A#3,B#4)[0] AS a1#11, myudf(A#3,B#4)[1] AS a2#12, myudf(A#3,B#4)[2] AS a3#13]
+- SerializeFromObject [knownnotnull(assertnotnull(input[0, org.apache.spark.sql.test.SQLTestData$TestData2, true])).a AS a#3, knownnotnull(assertnotnull(input[0, org.apache.spark.sql.test.SQLTestData$TestData2, true])).b AS b#4]
   +- ExternalRDD [obj#2]

一直不信,怎么会不这么不智能,具体原因是啥?该怎么避免?这个在上周六的直播分享里讲过了。

第三种情况:

这种也会经常遇到,并且也会经常被其他朋友问到能不能被优化

代码语言:javascript
复制
 // 其中用collect_set来代表聚合函数
select 
  collect_set(a)[0] as c1,  
  collect_set(a)[1] as c2, 
  collect_set(a)[3] as c3
from testdata2 
group by b

这里的collect_set(a)会执行几遍?

结论是

执行一遍。

这样类似的还有:count(xxx),count(distinct xxx) 等等,聚合函数在重复用时,不用担心,sparksql会给优化。所以,我们在写代码时就不用考虑再在外面写一层,从而避免多写一层,造成数据多流转一次的浪费。

看看吧,不同的情况,会有不同的优化结果,如果知道原理,就能避开一些坑。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-08-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据仓库践行者 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档