【问题标题】:Spark SQL: Empty table join with large table slowSpark SQL:空表连接与大表慢
【发布时间】:2021-09-16 18:53:01
【问题描述】:

我有两张桌子

  1. 交易表(按年份分区)
  2. 元数据表(所有键唯一无分区,30M条记录) 我的 Spark SQL 是
SELECT * FROM Transaction WHERE PARTITION_YEAR = 2022; (result: 0 record)

很快就能得到结果

SELECT * FROM Metadata WHERE KEY = "A"(结果:1 条记录)

2-3秒得到结果

最后

SELECT * FROM Transaction t LEFT JOIN Metadata m ON t.key = m.key WHERE t.PARTITION_YEAR = 2022;

很慢(3 分钟)

虽然

SELECT * FROM (SELECT * FROM Transaction WHERE PARTITION_YEAR = 2022) t LEFT JOIN Metadata m ON t.key = m.key;

还需等待(3 分钟)

【问题讨论】:

  • 似乎spark正在扫描所有文件,表格的文件格式是什么?如果不是这样,我会建议改成镶木地板,这样可以更好地进行扫描优化
  • 镶木地板格式。

标签: apache-spark apache-spark-sql hdfs


【解决方案1】:

根据您的查询行为,我猜您的文件格式是 parquet

SELECT * FROM Metadata WHERE KEY = "A" 

这就像一个支持 PUSHDOWN 过滤器的过滤器操作,它不会扫描整个表,而是快速查看您感兴趣的列 (KEY) 的 parquet 元数据 (RANGE) 并找出。

但是当你加入 Spark 时: 它必须将元数据的整个表放入内存,并且必须根据您的连接条件扫描和打乱数据。即联接不支持 PUSHDOWN 过滤器。


您的最后 2 个查询基本相同。 Spark 只会将 2022 年的数据带入内存。即使您的分区可能是空的,也会加载 30M 的 METADATA 记录。


如果你想避免空分区出现这种情况,你应该检查分区是否为空,然后只触发

最便宜/有效的检查方式:

val dfPartition = spark.sql("SELECT * FROM Transaction WHERE PARTITION_YEAR = 2022;")

if(!dfPartition.isEmpty()) // fastest. 
{
  //Fire your join query
}

【讨论】:

  • 我可以提示它在加载元数据之前检查事务表吗?或者做一些优化它。
  • 通过明确检查更安全。添加在答案中。
  • 我可以做类似“SELECT * FROM Transaction t LEFT JOIN (SELECT * FROM Metadata WHERE 0
  • 运行一次。我不确定 spark 的逻辑计划对于这个 SQL 会是什么样子。理想情况下,它不应超过 5 秒。
猜你喜欢
  • 2021-10-15
  • 2018-07-24
  • 1970-01-01
  • 2020-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-24
  • 1970-01-01
相关资源
最近更新 更多