Apache spark 如何连接两个JDBC表并避免交换?

Apache spark 如何连接两个JDBC表并避免交换?,apache-spark,apache-spark-sql,Apache Spark,Apache Spark Sql,我有一个类似ETL的场景,在这个场景中,我从多个JDBC表和文件中读取数据,并在源代码之间执行一些聚合和连接 在一个步骤中,我必须连接两个JDBC表。我试着做一些类似的事情: val df1=spark.read.formatjdbc .optionurl,Database.DB_URL .optionuser,Database.DB\u用户 .optionpassword,Database.DB_密码 .optiondbtable,表名 .optiondriver,Database.DB\u驱

我有一个类似ETL的场景,在这个场景中,我从多个JDBC表和文件中读取数据,并在源代码之间执行一些聚合和连接

在一个步骤中,我必须连接两个JDBC表。我试着做一些类似的事情:

val df1=spark.read.formatjdbc .optionurl,Database.DB_URL .optionuser,Database.DB\u用户 .optionpassword,Database.DB_密码 .optiondbtable,表名 .optiondriver,Database.DB\u驱动程序 .optionupperBound,data.upperBound .optionlowerBound,data.lowerBound .optionnumPartitions,data.numPartitions .optionpartitionColumn,data.partitionColumn 负载 val df2=spark.read.formatjdbc .optionurl,Database.DB_URL .optionuser,Database.DB\u用户 .optionpassword,Database.DB_密码 .optiondbtable,表名 .optiondriver,Database.DB\u驱动程序 .optionupperBound,data2.upperBound .optionlowerBound,数据2.lowerBound .optionnumPartitions,data2.numPartitions .optionpartitionColumn,数据2.partitionColumn 负载 df1.joindf2,Seqpartition\u key,id.show; 请注意,在这两种情况下,partitionColumn都是相同的-partition\u键

但是,当我运行此类查询时,我可以看到不必要的exchange计划已清除,以确保可读性:

df1.joindf2,Seqpartition_key,id.explainextended=true; 项目[许多领域] +-项目[partition_key10090L,iv_id10091L,last_update_timestamp10114,…更多字段] +-SortMergeJoin[partition_key10090L,id10091L],[partition_key10172L,id10179L],内部 :-*排序[partition_key10090L ASC NULLS FIRST,iv_id10091L ASC NULLS FIRST],false,0 :+-交换hashpartitioningpartition_key10090L,iv_id10091L,4 :+-*扫描JDBCRelationselect mods.id,23作为分区分区键,s.*从选项卡2 s[numPartitions=23][partition\u key10090L,id10091L,last\u update\u timestamp10114]推式筛选器:[*IsNotNullPARTITION\u键],ReadSchema:struct +-*排序[partition_key10172L ASC NULLS FIRST,id10179L ASC NULLS FIRST],false,0 +-交换hashpartitioningpartition\u key10172L,iv\u id10179L,4 +-*项目[partition_key10172L,id10179L…75个以上字段]
+-*扫描JDBCRelationselect mods.id,23作为分区_键,s.*从tab1 s[numPartitions=23][fields]PushedFilters:[*IsNotNullID,*IsNotNullPARTITION_键],ReadSchema:struct当前实现的日期源API没有向上游传递分区信息,因此即使数据可以在不进行洗牌的情况下合并,Spark无法使用此信息。因此,请假设:

JdbcRelation在读取时使用范围分区

这是不正确的。此外,Spark似乎使用相同的内部代码来处理基于范围的JDBC分区和基于谓词的JDBC分区。虽然前者可以转换为SortOrder,但后者通常可能与sparksql不兼容

如果有疑问,可以使用QueryExecution和内部RDD检索分区器信息:


这在未来可能会改变,SortMergeJoin表示数据集非常庞大。有多少张唱片?密钥是相同的,但是您如何知道分区和密钥在同一台机器上?如果没有您自己的自定义分区器(以某种方式是有状态的并在查询之间共享),这是可预测的吗?大声思考。@JacekLaskowski在测试数据集上,一个表中约有500万,第二个表中约有150万。它们都是用同一个partitionColumn读取的,所以它们应该是同一个节点-但是它是RangePartitioned,而不是HashPartitioned,也许这就是不同之处-它们应该是同一个节点,但是它是RangePartitioned,也许我的理解是错误的,但是在阅读之后我有一些分区,因此HashPartitioning应该提供与JDBCRelation所做的RangePartitioning相同的保证。我错了吗?@JacekLaskowski outputPartitioning是在您洗牌数据并获得ShuffledRowRDD时设置的。但我想你误解了我的意思——当我说分区规范时,我指的是用于准备语句的下限、上限、numPartitions。我看不出outputPartitioning和用于准备语句的下限、上限、numPartitions之间的区别。在我看来,它们是相互关联的,也就是说,您使用后者创建JDBC分区,而outputPartitioning在需要时保留或修改它们。@JacekLaskowski如果您考虑到JDBC源与其他数据源一样返回具有未知分划的Dataset,我不确定您在哪里看到这种关联。是的,理论上,这些信息可以传递到下游。事实并非如此,而且在实践中也不容易实现。在一般情况下,对整数进行排序当然是微不足道的。如果你想表达一些我一直想表达的观点,我会真诚地通知你 吃一些更明确的东西:
df.queryExecution.toRdd.partitioner