Sql server 如何使用varchar数据类型的partitionColumn读取scala spark上的表?

Sql server 如何使用varchar数据类型的partitionColumn读取scala spark上的表?,sql-server,scala,apache-spark,jdbc,Sql Server,Scala,Apache Spark,Jdbc,是否可以指定varchar数据类型的partitionColumn? 我要读取的表没有主键,所有列都是varchar数据类型。有没有办法将partitionColumn作为varchar类型从jdbc中读取 var finaldataframe = spark.read.format("jdbc") .option("driver", "com.microsoft.sqlserver.jdbc.SQLServerDriver") .option("database",db) .option("u

是否可以指定varchar数据类型的partitionColumn? 我要读取的表没有主键,所有列都是varchar数据类型。有没有办法将partitionColumn作为varchar类型从jdbc中读取

var finaldataframe = spark.read.format("jdbc")
.option("driver", "com.microsoft.sqlserver.jdbc.SQLServerDriver")
.option("database",db)
.option("url", url)
.option("dbtable", table_name)
.option("numPartitions", partitions)
.option("partitionColumn", pm_key)
.option("lowerbound", w_minLogID)
.option("upperbound", w_maxLogID)
.load() 
spark docs说:

partitionColumn必须是相关表中的数字、日期或时间戳列


但是有一些解决方法吗?

TL;DR此可选字段用于提高性能。如果数据集很小,可以跳过它。类似的功能可以通过为字符串列使用
谓词:Array[String]
参数来实现

val connectionProperties = new Properties()
connectionProperties.put("database", db)
connectionProperties.put("driver", "com.microsoft.sqlserver.jdbc.SQLServerDriver")

var finaldataframe = spark.read.jdbc(
    url = url,
    table = table_name,
    predicates = Array[String]("columnA like 'A%'", "columnB like 'B%'" )
    connectionProperties = connectionProperties
)

要理解为什么
partitionColumn
只允许使用类似数字的列,请查看spark如何从数据库中读取数据

默认情况下,spark将使用单个执行器连接到数据库,运行查询并开始提取结果。如果您希望从数据库中提取大型数据集,则此方法不适用,因为

  • 只有一个执行器正在提取数据
  • 提取的数据必须重新分区/洗牌给其他执行者
如果多个执行器并行地从数据库中提取部分数据,则可以改进这一点。假设您要运行查询
从产品中选择id、prod\u name
,并且此表有一百万行。
您可以告诉spark
numPartitions
4
partitionColumn
id
为整数,
lowerbound
1和
upperbound
1000000

现在spark将计算每个执行者需要提取250K条记录

(上界-下界+1)/numPartitions
=(1000000-1+1)/4
=250000

使用此命令,第一个执行器将启动查询

select * 
from 
  (
    select id, prod_name 
    from products
  ) 
where id >= 1 and id<=250000


为了在spark JDBC数据读取中实现并行性,必须指定numPartitions、partitionColumn、lowerBound和upperBound。()否则spark总是执行一个JDBC连接,并将所有数据读取到单个分区中。在这种情况下,只使用一个执行器,无法实现并行性。 例如

在这种情况下,只有一个查询被激发到其中一个执行器中的数据库,因此没有并行性。 要实现并行性,请使用以下代码

spark.sqlContext.read
    .option("partitionColumn", "amount")
    .option("lowerBound", 0).option("upperBound", 1000)
    .option("numPartitions", 10)
    .jdbc(url), "( select * from transaction ) as s", connectionProperties)
上述查询将在spark执行器之间创建10 db连接,并将数据并行读取到spark内存

select * from transaction where amount>=0 and amount<100.
select * from transaction where amount>=100 and amount<200...
上述代码将在spark执行器之间创建10 DB连接。 当我们在分区计数上对行数进行mod时,我们总是会得到从0到9的值。通过这样做,数据被并行读取,并均匀地分布在分区之间。 检查分区

import spark.implicits._
df
  .rdd
  .mapPartitionsWithIndex { case (i, rows) => Iterator((i, rows.size)) }
  .toDF("partition_number", "number_of_records")
  .show
spark.sqlContext.read.jdbc(url, "(select * from transaction ) as s", connectionProperties).
spark.sqlContext.read
    .option("partitionColumn", "amount")
    .option("lowerBound", 0).option("upperBound", 1000)
    .option("numPartitions", 10)
    .jdbc(url), "( select * from transaction ) as s", connectionProperties)
select * from transaction where amount>=0 and amount<100.
select * from transaction where amount>=100 and amount<200...
val partitionCount = 10
val partitionKey="partitionKey" 
spark.sqlContext.read
        .option("partitionColumn", partitionKey)
        .option("lowerBound", 0).option("upperBound", partitionCount)
        .option("numPartitions", partitionCount)
        .jdbc(url), s"( select mod(row_number() OVER (),$partitionCount) as $partitionKey, * from transaction ) as s", connectionProperties).drop(partitionKey)
import spark.implicits._
df
  .rdd
  .mapPartitionsWithIndex { case (i, rows) => Iterator((i, rows.size)) }
  .toDF("partition_number", "number_of_records")
  .show