Apache spark Spark SQL中连接大型表的优化方法是什么

Apache spark Spark SQL中连接大型表的优化方法是什么,apache-spark,apache-spark-sql,Apache Spark,Apache Spark Sql,我需要使用Spark SQL或Dataframe API连接表。需要知道实现它的最佳方式是什么 情况是: 所有数据都以ORC格式(基本数据帧和参考文件)显示在配置单元中 我需要将从Hive读取的一个基本文件(Dataframe)与11-13个其他参考文件连接起来,以创建一个大的内存结构(400列)(大小约为1 TB) 实现这一目标的最佳方法是什么?如果有人遇到类似问题,请分享您的经验。分区源代码使用哈希分区或范围分区,或者如果您更了解连接字段,您可以编写自定义分区。分区将有助于避免在连接期间重新

我需要使用Spark SQL或Dataframe API连接表。需要知道实现它的最佳方式是什么

情况是:

  • 所有数据都以ORC格式(基本数据帧和参考文件)显示在配置单元中
  • 我需要将从Hive读取的一个基本文件(Dataframe)与11-13个其他参考文件连接起来,以创建一个大的内存结构(400列)(大小约为1 TB)

  • 实现这一目标的最佳方法是什么?如果有人遇到类似问题,请分享您的经验。

    分区源代码使用哈希分区或范围分区,或者如果您更了解连接字段,您可以编写自定义分区。分区将有助于避免在连接期间重新分区,因为来自同一分区的数据跨表存在于同一位置。 兽人肯定会帮助这项事业。
    如果这仍然会导致溢出,请尝试使用比磁盘快的tachyon

    我对如何优化连接的默认建议是:

  • 如果可以,请使用广播连接(请参阅)。从您的问题来看,您的表似乎很大,不能选择广播连接

  • 考虑使用一个非常大的集群(你可能认为它更便宜)$250现在(2016年6月)在EC2现货市场上购买了约24小时的800核、6Tb RAM和许多SSD。在考虑大数据解决方案的总成本时,我发现人们往往严重低估了他们的时间

  • 使用相同的分区器。有关联合编组联接的信息,请参见

  • 如果数据庞大,并且/或者您的集群无法增长,甚至(3)以上都会导致OOM,请使用双通道方法。首先,使用分区表(
    dataframe.write.partitionBy()
    )重新分区数据并持久化。然后,在循环中串行地连接子分区,“附加”到相同的最终结果表

  • 旁注:我在上面说“追加”是因为在生产中我从不使用
    SaveMode.Append
    。它不是幂等的,这是一件危险的事情。我使用
    SaveMode.Overwrite
    深入到分区表树结构的子树中。在2.0.0和1.6.2之前,您必须删除
    \u SUCCESS
    ,否则元数据文件或动态分区发现将阻塞

    希望这有帮助。

    Spark用于加入大表。它包括对两个表上的每一行进行散列,并将具有相同散列的行洗牌到同一分区中。在这里,密钥在两侧进行排序,并应用sortMerge算法。据我所知,这是最好的办法

    为了大大加快排序速度,将大型数据集编写为带有预扣和预排序选项(相同数量的分区)的配置单元表,而不是平面拼花地板数据集

    表a
    .重新分区(2200元,A元,B元)
    写
    .巴克比(2200,“A”、“B”)
    .sortBy(“A”、“B”)
    .mode(“覆盖”)
    .格式(“拼花地板”)
    .saveAsTable(“我的数据库表a”)
    表B
    .重新分区(2200元,A元,B元)
    写
    .巴克比(2200,“A”、“B”)
    .sortBy(“A”、“B”)
    .mode(“覆盖”)
    .格式(“拼花地板”)
    .saveAsTable(“我的数据库表”)
    
    与优势相比,编写预扣/预排序表的间接成本适中

    默认情况下,底层数据集仍然是parquet,但是配置单元元存储(可以是AWS上的Glue元存储)将包含关于表的结构的宝贵信息。因为所有可能的“可连接”行都是同位的,Spark不会洗牌预排序的表(节省了很多!),也不会对表分区内预排序的行进行排序

    val join=tableA.join(tableB,Seq(“A”,“B”))
    
    查看有无预扣的执行计划

    这不仅可以在连接过程中节省大量时间,还可以在相对较小的集群上运行非常大的连接,而无需OOM。在Amazon,我们大部分时间都在prod中使用它(仍有一些情况下不需要它)

    要了解有关预扣带/预分拣的更多信息:


    谢谢你,我会考虑这些问题。只是好奇,这是AWS上的6TB+800核心一台服务器吗?它是一个群集,而不是一台服务器。是的,在AWS上。如果您能用一个例子来解释您的第四点(在循环中串行地连接子分区,“附加”到相同的最终结果表),我将不胜感激。请以两个dataframe为例详细说明一下,以及如何循环passes@vikrantrana我没有足够的带宽来实现这一点,但基本思想很简单:一个大的USING连接可以分解为连接列空间子集的较小连接的并集。通过对联接的左侧和右侧应用一致分区来构建子集。例如,如果您要加入一个整数ID,您可以按ID除以某个数字进行分区,例如,
    df.withColumn(“par_ID”,ID%256)。重新分区(256,'par_ID”)。write.partitionBy(“par_ID”)…
    然后迭代
    持久化。选择('par_ID.)。清除。收集
    加入每个分区并再次持久化。然后是工会。