解决spark sql关联(join)查询使用“or“缓慢的问题

本文介绍了一种使用Spark对大规模数据集进行高效关联的方法。通过优化SQL查询,将原本需要数天才能完成的任务缩短至几分钟内完成。具体优化手段包括拆分复杂条件、使用缓存以及避免使用OR语句。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.需求描述

将a表的数据与b表的两个字段进行关联,输出结果

a表数据约24亿条

b表数据约30万条

2.优化效果

优化后执行时间从数天减少到数分钟

3.资源配置

spark 1.4.1

200core,600G RAM

4.代码简化版(优化前)

sqlContext.sql("name,ip1,ip2 as ip from table_A where name is not null and ip2 is not null or ip2 is not null) group by name,ip1,ip2").registerTempTable("a")

sqlContext.read.parquet("table_B").registerTempTable("b")

sqlContext.sql('''
select 
        ip,
        count(1) as cnt 
from 
        (select 
                bb.ip as ip,
                aa.name as name 
        from 
                (select * from b where ip != '')bb left join (select * from a)aa on (bb.ip=aa.ip2 or bb.ip=aa.ip1)
        group by 
                bb.ip,
                aa.name)
group by 
        ip
''').write.json("result")

5.代码简化版(优化后)

后来经过排查发现是使用or语句导致的运行缓慢,于是将两个条件查询注册成两张表,然后union成一张表,union操作其实只是合并两个rdd的分区,基本没有什么开销。然后在对这张表进行关联操作

代码如下:

//查询出需要的字段并进行缓存,因为下面要查询2次
sqlContext.sql("CACHE TABLE all AS select name,ip1,ip2 from table_A where name is not null and (ip1 is not null or ip2 is not null) group by name,ip1,ip2")

sqlContext.sql("select name,ip1 from all group by name,ip1").registerTempTable("temp1")

sqlContext.sql("select name,ip2 from all group by name,ip2").registerTempTable("temp2")

sqlContext.sql("select name,ip from (select * from temp1 union all select * from temp2)a group by name,ip").registerTempTable("a")

sqlContext.read.parquet("table_B").registerTempTable("b")

sqlContext.sql('''
select 
        ip,
        count(1) as cnt 
from 
        (select 
                bb.ip as ip,
                aa.name as name
        from 
                (select * from b where ip != '')bb left join (select * from a)aa on bb.ip=aa.ip
        group by 
                bb.ip,
                aa.name)
group by 
        ip
''').write.json("result")
### 多数据源操作概述 在Apache Spark SQL环境中处理多个数据源是一项常见需求,允许用户从不同类型的存储系统读取和写入数据。通过Spark SQL可以轻松集成多种数据源,包括但不限于Hive、JSON文件、Parquet文件以及JDBC连接的传统数据库[^1]。 对于多数据源的操作主要涉及以下几个方面: #### 数据加载与保存 - **加载外部数据**:可以通过`DataFrameReader`接口指定不同的格式来读取来自各种来源的数据到DataFrame对象中。 ```scala val dfFromJson = spark.read.json("examples/src/main/resources/people.json") ``` - **保存结果至目标位置**:利用`DataFrameWriter`类可将转换后的数据写出给定路径下的特定文件格式或者关系型数据库格里。 ```scala df.write.mode(SaveMode.Overwrite).jdbc(url=jdbcUrl, table="my_table", connectionProperties=connectionProps) ``` #### 跨数据源查询优化 当涉及到跨异构数据源执行复杂SQL查询时,为了提高性能应该考虑如下策略: - 使用广播变量加速小规模维度与其他大规模事实之间的关联运算; - 对频繁访问的数据集实施缓存机制减少重复扫描开销; #### 实现案例分析 假设存在两个独立的数据源——一个是位于本地磁盘上的CSV文档集合示销售记录,另一个则是远程MySQL服务器上托管的产品目录信息。现在希望构建一份报告统计每种商品类别在过去一个月内的销售额情况,则具体做法如下所示: ```sql -- 创建临时视图以便后续引用 CREATE OR REPLACE TEMP VIEW sales AS SELECT * FROM csv.`/path/to/sales/*.csv`; CREATE OR REPLACE TEMP VIEW products AS SELECT * FROM jdbc.`jdbc:mysql://dbserver/products`; -- 执行JOIN并聚合得到最终报 SELECT p.category, SUM(s.amount) as total_sales FROM sales s JOIN products p ON s.product_id=p.id WHERE date >= DATE_SUB(CURRENT_DATE(), 30) GROUP BY p.category; ``` 上述例子展示了如何借助于Spark SQL强大的抽象能力简化了原本复杂的ETL流程,并且能够高效地完成对分布式的海量数据进行实时分析的任务。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值