Spark 性能调优实战
吴磊
前 FreeWheel 机器学习团队负责人
8808 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 36 讲
Spark 性能调优实战
15
15
1.0x
00:00/00:00
登录|注册

28 | 大表Join大表(一):什么是“分而治之”的调优思路?

你好,我是吴磊。
上一讲,我们探讨了“大表 Join 小表”场景的调优思路和应对方法。那么,除了大表 Join 小表的场景,数据分析领域有没有“大表 Join 大表”的场景呢?确实是有的,它指的是参与 Join 的两张体量较大的事实表,尺寸相差在 3 倍以内,且全部无法放进广播变量。
但是通常来说,在数据分析领域,用一张大表去关联另一张大表,这种做法在业内是极其不推荐的。甚至毫不客气地说,“大表 Join 大表”是冒天下之大不韪,犯了数据分析的大忌。如果非要用“大表 Join 大表”才能实现业务逻辑、完成数据分析,这说明数据仓库在设计之初,开发者考虑得不够完善、看得不够远。
不过,你可能会说:“我刚入职的时候,公司的数仓就已经定型了,这又不是我的锅,我也只能随圆就方。”为了应对这种情况,今天这一讲我们就来说说,当你不得不面对“大表 Join 大表”的时候,还有哪些调优思路和技巧。
要应对“大表 Join 大表”的计算场景,我们主要有两种调优思路。一种叫做“分而治之”,另一种我把它统称为“负隅顽抗”。今天这一讲,我们先来说说“分而治之”,“负隅顽抗”我们留到下一讲再去展开。
值得一提的是,即便你不需要去应对“大表 Join 大表”这块烫手的山芋,“分而治之”与“负隅顽抗”所涉及的调优思路与方法,也非常值得我们花时间去深入了解,因为这些思路与方法的可迁移性非常强,学习过后你会发现,它们完全可以拿来去应对其他的应用场景。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

在数据分析领域,处理大表Join大表的场景一直备受关注。本文介绍了针对这一挑战的调优思路——“分而治之”,通过将复杂的Shuffle Join转化为多个Broadcast Joins,以提升作业执行性能。关键在于内表的均匀拆分和选择合适的拆分列,同时避免外表的重复扫描。文章强调了拆分列基数的重要性,提出了以日期列作为拆分列的建议。此外,还介绍了利用DPP机制和Broadcast Joins来有效应对数据倾斜问题。这些调优思路不仅适用于“大表Join大表”场景,也可应用于其他应用场景。通过实战案例展示了如何将关联查询转化为“大表Join小表”,并有效提升性能。总之,本文提供了实用的调优方法,对于处理大表Join大表的性能优化具有重要参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Spark 性能调优实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(12)

  • 最新
  • 精选
  • 赵鹏举
    1 优化过程是scalla写的,纯SQL有没有实现吗? 2 spark版本为2.4.3有办法达到类似效果吗?

    作者回复: 1)SQL也是可以的哈~ 不过得用到spark-sql CLI,或是Beeline这样的客户端 2)2.x还不行,这里需要利用到3.x才有的DPP机制

    2021-12-21
    4
  • wow_xiaodi
    老师,对于评论区里的说到的colocated joins,可否简单说下运行机制?

    作者回复: 好问题,colocated joins很有意思,它其实特指的是这种情况,参与Join的两张表: 1. 并行度一样 2. 以Join Key为基准,数据分布一致 满足这两个条件的两张表参与的Join,就叫colocated joins。 其实,说白了,就是两张表的数据分布完全一致(相对Join Key来说)。因此,对他们做关联,自然不再需要Shuffle环节,因为两张表的数据分片都已经相互“配好对”了,两边Join Keys相同的数据记录,都分布在同样Executors中。

    2021-08-14
    4
    2
  • jerry guo
    如果外表是bucket表,内表也是相同的bucket表,那么也是可以避免多次扫描外表的。这种情况说不定币shj更好,因为不需要shuffle

    作者回复: 对,非常好~ 满分💯!你说的这个,其实就是collocated joins,collocated joins是一种特殊的joins,就是参与Join的两表提前按照Join Key都做了重分布,那么再次关联的时候,自然不会引入Shuffle~ 不过,对于两个bucket表,要求他们的bucket id是一致的,都要包含Join Key,否则关联的时候还是会有Shuffle。

    2021-05-17
    2
    2
  • licl1008
    老师 现实中用orderID作为分区键 是不是分区会太多 感觉订单ID基数很大

    作者回复: 好问题,DPP确实有这方面的限制,就是要求Join Key本身是分区键,这个要求确实比较苛刻。Join Key和分区键确实本身是一对矛盾,因为通常来说,Join Key的cardinality都不小,而分区键却要求cardinality不能太大。 你说的是对的,我们这个例子其实举的不好,这里为了demo DPP,我们选择了orderID,但实际上就像你说的,orderID本身的cardinality太大了,不适合做分区键。 所以说,利用DPP机制有个很重要的前提,就是数仓的设计,也就是结合后续常用的查询,提前把表结构设计好。这个表结构的设计,就需要考虑Join Keys和分区键的博弈~

    2021-05-17
    2
  • 威猛的小老虎
    笛卡尔积 如何优化呢

    作者回复: 唯一的办法是把CPJ转化为BNLJ,如果内表不够小,没法广播,必须要用CPJ来实现,坦白说,还真没什么好办法。这也是我们为什么要极力避免CPJ的原因~

    2021-05-24
    2
    1
  • Sam
    问题回答: 除了shuffle,想不出其他办法....哭~

    作者回复: 还有一种思路,就是系统集成。 之前有一个内存分布式文件系统,叫Tachyon,后来改名叫Alluxio,可以理解为内存里面的HDFS。它提供内存级别的文件系统。 Alluxio不少公司在用,就用来加速数据访问的,他们提前把“热数据”从HDFS加载到Alluxio,然后Spark再从Alluxio访问分布式内存文件,把磁盘I/O变成了内存访问。读取效率自然能提升不少。 当然,做这种系统集成的前提是“有钱”,得有足够的预算来购置大量内存,不过,还是那句话,调优最重要的是思路和手段,每种方法都有其优缺点。确实有大厂宁愿多花钱买内存来节省时间。 总之,这种系统集成的思路也是一种优化选项,在条件具备的时候,不妨加以考虑~ 其实沿着这个思路,你还可以发现更多集成的可能,Alluxio这里仅仅是举个例子加以说明,其实咱们作为开发者,平时要多关注技术动态和进展,开阔眼界和思路,我觉得这一点非常重要,个人观点哈~ 不一定对~ 一个新技术,不管将来用不用得上,多了解、熟悉一些,总是不吃亏的~

    2021-07-17
    2
  • 空格
    老师,demo中按照date循环查询的sql直接使用spark sql执行可以实现外边扫描一次嘛?

    作者回复: 需要结合DPP机制才行哈~

    2021-07-06
    2
  • orangelin
    虽然orderid作为分区键有点太多,是否可以考虑按照orderid的数据特征,比如id是字母结尾亦或者是数字结尾,按这个列去做分区是可以减少一定的分区数,举个例子,我的分区关联条件是 数字id的尾号,那么关联的分区最多就是从0-9的10个数字,用这种方式的话是可以触发dpp呢

    作者回复: 这样做确实能降低分区键的Cardinality,从而缓解分区存储的压力。不过按照尾号对orderId做关联,业务逻辑上似乎不成立。因为一般来说,肯定是orderId要完全一致Join在一起才会有意义,否则,仅仅是尾号相同、但实际是不同的orderId,他们join在一起其实业务逻辑上说不通的~ 不过,话说回来,如果确实关联条件就是orderId的尾号,那么在运行时也是会触发DPP的,毕竟你说的这种场景是满足DPP的各种前提条件的~

    2021-06-24
  • 天翼
    请问一下,老师的内表和外表的定义是怎么来的,是根据表的大小吗?还是说有什么其他的判断依据?

    作者回复: 是的,主要是表大小,通常来说,大多数数据库引擎,都会把尺寸比较大的表,当作外表;而尺寸较小的表,当作内表。

    2021-05-24
  • 斯盖丸
    老师,你的例子里,tx表的join条件没有用到date,而DPP的实现必须依赖join条件里包含分区字段,也就是date才可以的,这样好像不能实现优化吧?

    作者回复: 这里面tx表是事实表哈,它的分区键是orderId,如下所示: //lineitems表的关键字段 orderId: Int //分区键 txId: Int itemId: Int price: Float quantity: Int Join key是orderId,也就是on tx.orderId = o.orderId,因此就这个例子来说,是可以触发DPP的,当然,tx表选orderId作为分区键,是值得商榷的。

    2021-05-17
    3
收起评论
显示
设置
留言
12
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部