> 文章列表 > Spark通过jdbc性能调优--采用分区的方式从oracle读数据

Spark通过jdbc性能调优--采用分区的方式从oracle读数据

Spark通过jdbc性能调优--采用分区的方式从oracle读数据

spark通过jdbc读取Oracle,当数据量很大的时候会出现两个问题:

  1. 读取数据异常缓慢,甚至卡死
  2. 大表中进行操作也会出现OOM的问题

调优

常规的读取数据库的方式如下

ods_bdz = spark.read.format(“jdbc”)
.option(“url”, “jdbc:oracle:thin:@”+dbstring)
.option(“dbtable”, “ODS_BDZ”)
.option(“user”, dbuser)
.option(“password”, dbpasswd)
.load()

常规jdbc读取表的时候只有一个分区在执行,也就是只有一个excutor在工作,没有把spark并行操作的特性发挥出来
通过查阅sparksql官方文档,查阅到如下的jdbc操作数据库的连接属性

属性名 含义
url 需要连接的JDBC URL
dbtable 需要读取的JDBC表。注意,任何可以填在SQL的where子句中的东西,都可以填在这里。(既可以填完整的表名,也可填括号括起来的子查询语句)
driver JDBC driver的类名。这个类必须在master和worker节点上都可用,这样各个节点才能将driver注册到JDBC的子系统中。
partitionColumn, lowerBound, upperBound, numPartitions 这几个选项,如果指定其中一个,则必须全部指定。他们描述了多个worker如何并行的读入数据,并将表分区。partitionColumn必须是所查询的表中的一个数值字段。注意,lowerBound和upperBound只是用于决定分区跨度的,而不是过滤表中的行。因此,表中所有的行都会被分区然后返回。
fetchSize JDBC fetch size,决定每次获取多少行数据。在JDBC驱动上设成较小的值有利于性能优化(如,Oracle上设为10)

所以我们可以采取上表中所示的分区读表的方式来优化这个问题

  1. 当有数值字段的时候
    这种情况是最好进行处理的,直接按数值字段分区处理即可。在此需要增加四个属性:numPartitions,partitionColumn,lowerBound,upperBound。
    读数代码如下:
ods_bdz = spark.read.format(“jdbc”)
.option(“url”, “jdbc:oracle:thin:@”+dbstring)
.option(“dbtable”, “ods_bdz”)
.option(“user”, dbuser)
.option(“password”, dbpasswd)
.option(“numPartitions”, 20)
.option(“partitionColumn”, “part_num”)
.option(“lowerBound”, 1)
.option(“upperBound”, 20)
.load()

因为分区数是20,所以在oracle数据里面就会生成20条SQL,每条sql又一个excutor取读取。从未实现了分区读取的优化目的:

Select * from ods_bdz where part_num<2;
Select * from ods_bdz where part_num<3 and part_num>=2;
Select * from ods_bdz where part_num<4 and part_num>=3;
……
Select * from ods_bdz where part_num>=20;

  1. 没有数值字段的时候,采用ROWID自定义分区键
ods_bdz = spark.read.format(“jdbc”)
.option(“url”, “jdbc:oracle:thin:@”+dbstring)
.option(“dbtable”,(SELECT MOD(ASCII(SUBSTR(ROWID,-1)),20) RN,A.* FROM tab A))
.option(“user”, dbuser)
.option(“password”, dbpasswd)
.option(“numPartitions”, 20)
.option(“partitionColumn”, “RN”)
.option(“lowerBound”, 0)
.option(“upperBound”, 20)
.load()

采用ROWID的最后一位的ASCII码对20进行取模,得到的模是0-19之间的,这样就可以将这个值作为分区键,每条数据记录将会划分到固定的分区。