背景
有如下的数据查询场景。
表结构
create table order (order_id long, customer_id long) partitioned by (date string);
要查询当天有订单,但是前一天没有订单的用户在当天的订单记录。
数据分析的同事编写的最初版本的SQL如下
select * from order where date='2021-07-17' and customer_id not in (
select customer_id from order where date='2021-07-16');
这张表每天的数据量大概在百万级别。
SQL在10个4Core16GB的executor上运行了5个多小时依然没有结束。
分析
通过查看SQL语句的执行计划基本就可以判断性能瓶颈所在。
| == Physical Plan ==
BroadcastNestedLoopJoin BuildRight, LeftAnti, ((customer_id#370L = customer_id#373L) || isnull((customer_id#370L = customer_id#373L)))
:- Scan hive default.order [order_id#369L, customer_id#370L, date#371], HiveTableRelation `default`.`order`, org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe, [order_id#369L, customer_id#370L], [date#371], [isnotnull(date#371), (date#371 = 2021-07-17)]
+- BroadcastExc

本文探讨了一个Spark SQL查询优化案例,针对单字段NOT IN子查询导致的性能问题。原始SQL在处理百万级别数据时运行超过5小时。通过分析发现,优化器将其转化为BroadcastNestedLoopJoin,造成效率低下。解决方案是将NOT IN子查询改写为LEFT JOIN,变为SortMergeJoin,降低时间复杂度到O(n + nlogn)。在Spark 3.1.0中虽有改进,但在大数据量或Spark 2.4.0版本下仍需手动优化。

1066

被折叠的 条评论
为什么被折叠?



