文章最前: 我是Octopus,这个名字来源于我的中文名--章鱼;我热爱编程、热爱算法、热爱开源。所有源码在我的个人github ;这博客是记录我学习的点点滴滴,如果您对 Python、Java、AI、算法有兴趣,可以关注我的动态,一起学习,共同进步。
相关文章:
-
LEFT ANTI JOIN的使用
-
Spark SQL优化:NOT IN子查询优化解决
-
hivesql-dayofweek 函数
-
percentile_approx 聚合函数
背景
有如下的数据查询场景。
SELECT a
,b
,c
,d
,e
,f
FROM xxx.BBBB
WHERE dt = '${zdt.addDay(0).format('yyyy-MM-dd')}'
AND predict_type
not IN
(
SELECT
distinct a
FROM
xxx.AAAAA
WHERE dt = '${zdt.addDay(0).format('yyyy-MM-dd')}'
)
分析
通过查看SQL语句的执行计划基本就可以判断性能瓶颈所在。
| == Physical Plan ==
BroadcastNestedLoopJoin BuildRight,
Spark SQL的优化器最终将SQL优化为了一个BroadcastNestedLoopJoin。
实际上就是在对JOIN两侧的数据做笛卡尔积运算。时间复杂度为O(),过滤前的结果集行数达到了万亿级别。
优化方法
尝试将NOT IN子查询改写成了LEFT JOIN形式
SELECT a.*
FROM
(
SELECT a
,b
,c
,d
,e
,f
FROM xxx.BBBB
WHERE dt = '${zdt.addDay(0).format('yyyy-MM-dd')}'
) a
LEFT JOIN
(
SELECT c
FROM xxx.AAAA
WHERE dt = '${zdt.addDay(0).format('yyyy-MM-dd')}'
) b
ON a.c = b.c
WHERE b.c is null
执行计划如下:
Filter is null(#391L)
+- SortMergeJoin
可以看到,JOIN方式变成了SortMergeJoin。
SortMergeJoin的原理是对JOIN两侧的数据排序后在做归并。
不妨假设:
排序的时间复杂度为O(nlogn)。
则SortMergeJoin整体的时间复杂度为O(n + nlogn),依然是百万级数据量的过滤计算。
在数据库查询优化中,"Broadcast Nested Loop Join" 和 "Sort Merge Join" 是两种不同的关联操作算法。
Broadcast Nested Loop Join:
在这种连接算法中,一张表被广播到其他所有的节点上,然后与每个节点上的本地数据进行嵌套循环连接。这通常适用于一个小表和一个大表的连接,其中小表的数据可以很容易地广播到所有节点上。
优势:
1. 适用于小表连接: 当一个表很小而另一个表很大时,广播小表可以减少网络传输和数据传输开销。
2. 简单性: 实现相对简单,不需要进行大规模数据排序。
3. 内存友好: 不需要大量的内存,因为每次只处理小表的一行。
Sort Merge Join:
这是一种更加通用的连接算法,它不涉及表的广播,而是将连接的列进行排序,然后按照排序结果进行逐对比较,从而执行连接操作。
优势:
1. 适用于大表连接:当两个表的大小都比较大时,Sort Merge Join 可以更好地处理连接操作,因为不需要将整个表广播到各个节点。
2. 高效的顺序访问:由于涉及数据的排序,Sort Merge Join 可以更好地利用磁盘预读,提高磁盘数据访问效率。
3. 稳定性:对于不同数据分布的情况,Sort Merge Join 的性能通常比 Broadcast Nested Loop Join 更稳定。文章来源:https://www.toymoban.com/news/detail-754801.html
所以,Broadcast Nested Loop Join 适用于小表和大表之间的连接,而 Sort Merge Join 则更适合连接两个较大的表。但请注意,具体的性能取决于数据分布、硬件配置和数据库管理系统的优化能力。在实际情况中,优化器可能会根据统计信息和其他因素来选择最适合的连接算法。文章来源地址https://www.toymoban.com/news/detail-754801.html
到了这里,关于Spark SQL优化:NOT IN子查询优化解决的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!