一、二、三、四标题原文地址:

简书:wuli_小博:Spark JDBC系列–取数的四种方式



一、单分区模式

函数:

def jdbc(url: String, table: String, properties: Properties): DataFrame

使用示例:

val url = "jdbc:mysql://mysqlHost:3306/database"
val tableName = "table" // 设置连接用户&密码
val prop = new java.util.Properties
prop.setProperty("user","username")
prop.setProperty("password","pwd") // 取得该表数据
val jdbcDF = sqlContext.read.jdbc(url,tableName,prop) // 一些操作
....

从入参可以看出,只需要传入JDBC URL、表名及对应的账号密码Properties即可。但是计算此DF的分区数后发现,这种不负责任的写法,并发数是1

jdbcDF.rdd.partitions.size=1

操作大数据集时,spark对MySQL的查询语句等同于可怕的:select * from table; ,而单个分区会把数据都集中在一个executor,当遇到较大数据集时,都会产生不合理的资源占用:MySQL可能hang住,spark可能会OOM,所以不推荐生产环境使用;

二、指定Long型column字段的分区模式

函数:

def jdbc(
url: String,
table: String,
columnName: String,
lowerBound: Long,
upperBound: Long,
numPartitions: Int,
connectionProperties: Properties): DataFrame

使用id做分片字段的示例:

val url = "jdbc:mysql://mysqlHost:3306/database"
val tableName = "table"
val columnName = "id"
val lowerBound = getMinId()
val upperBound = getMaxId()
val numPartitions = 200 // 设置连接用户&密码
val prop = new java.util.Properties
prop.setProperty("user","username")
prop.setProperty("password","pwd") // 取得该表数据
val jdbcDF = sqlContext.read.jdbc(url,tableName, columnName, lowerBound, upperBound,numPartitions,prop) // 一些操作
....

从入参可以看出,通过指定 id 这个数字型的column作为分片键,并设置最大最小值和指定的分区数,可以对数据库的数据进行并发读取。是不是numPartitions传入多少,分区数就一定是多少呢?其实不然,通过对源码的分析可知:

if upperBound-lowerBound >= numPartitions:
jdbcDF.rdd.partitions.size = numPartitions
else
jdbcDF.rdd.partitions.size = upperBound-lowerBound

拉取数据时,spark会按numPartitions均分最大最小ID,然后进行并发查询,并最终转换成RDD,例如:

入参为:
lowerBound=1, upperBound=1000, numPartitions=10 对应查询语句组为:
JDBCPartition(id < 101 or id is null,0),
JDBCPartition(id >= 101 AND id < 201,1),
JDBCPartition(id >= 201 AND id < 301,2),
JDBCPartition(id >= 301 AND id < 401,3),
JDBCPartition(id >= 401 AND id < 501,4),
JDBCPartition(id >= 501 AND id < 601,5),
JDBCPartition(id >= 601 AND id < 701,6),
JDBCPartition(id >= 701 AND id < 801,7),
JDBCPartition(id >= 801 AND id < 901,8),
JDBCPartition(id >= 901,9)

建议在使用此方式进行分片时,需要评估好 numPartitions 的个数,防止单片数据过大;同时需要column字段的索引建立情况,防止查询语句出现慢SQL影响取数效率。

如果column的数字是离散型的,为了防止拉取时出现过多空分区,以及不必要的一些数据倾斜,需要使用特殊手段进行处理,具体可以参考Spark JDBC系列–读取优化。

三、高自由度的分区模式

函数:

def jdbc(
url: String,
table: String,
predicates: Array[String],
connectionProperties: Properties): DataFrame

使用给定分区数组的示例:

  /**
* 将近90天的数据进行分区读取
* 每一天作为一个分区,例如
* Array(
* "2015-09-17" -> "2015-09-18",
* "2015-09-18" -> "2015-09-19",
* ...)
**/
def getPredicates = { val cal = Calendar.getInstance()
cal.add(Calendar.DATE, -90)
val array = ArrayBuffer[(String,String)]()
for (i <- 0 until 90) {
val start = new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime())
cal.add(Calendar.DATE, +1)
val end = new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime())
array += start -> end
}
val predicates = array.map {
case (start, end) => s"gmt_create >= '$start' AND gmt_create < '$end'"
} predicates.toArray
} val predicates = getPredicates
//链接操作
...

从函数可以看出,分区数组是多个并行的自定义where语句,且分区数为数据size:

jdbcDF.rdd.partitions.size = predicates.size

建议在使用此方式进行分片时,需要评估好 predicates.size 的个数,防止防止单片数据过大;同时需要自定义where语句的查询效率,防止查询语句出现慢SQL影响取数效率。

四、自定义option参数模式

函数示例:

val jdbcDF = sparkSession.sqlContext.read.format("jdbc")
.option("url", url)
.option("driver", "com.mysql.jdbc.Driver")
.option("dbtable", "table")
.option("user", "user")
.option("partitionColumn", "id")
.option("lowerBound", 1)
.option("upperBound", 10000)
.option("fetchsize", 100)
.option("xxx", "xxx")
.load()

从函数可以看出,option模式其实是一种开放接口,spark会根据具体的参数,来决定使用上述三种方式中的某一种。

五、JDBC To Other Databases

Spark官方API文档:

JDBC To Other Databases

5.1Scala

// Note: JDBC loading and saving can be achieved via either the load/save or jdbc methods
// Loading data from a JDBC source
val jdbcDF = spark.read
.format("jdbc")
.option("url", "jdbc:postgresql:dbserver")
.option("dbtable", "schema.tablename")
.option("user", "username")
.option("password", "password")
.load() val connectionProperties = new Properties()
connectionProperties.put("user", "username")
connectionProperties.put("password", "password")
val jdbcDF2 = spark.read
.jdbc("jdbc:postgresql:dbserver", "schema.tablename", connectionProperties)
// Specifying the custom data types of the read schema
connectionProperties.put("customSchema", "id DECIMAL(38, 0), name STRING")
val jdbcDF3 = spark.read
.jdbc("jdbc:postgresql:dbserver", "schema.tablename", connectionProperties) // Saving data to a JDBC source
jdbcDF.write
.format("jdbc")
.option("url", "jdbc:postgresql:dbserver")
.option("dbtable", "schema.tablename")
.option("user", "username")
.option("password", "password")
.save() jdbcDF2.write
.jdbc("jdbc:postgresql:dbserver", "schema.tablename", connectionProperties) // Specifying create table column data types on write
jdbcDF.write
.option("createTableColumnTypes", "name CHAR(64), comments VARCHAR(1024)")
.jdbc("jdbc:postgresql:dbserver", "schema.tablename", connectionProperties)

5.2Java

// Note: JDBC loading and saving can be achieved via either the load/save or jdbc methods
// Loading data from a JDBC source
Dataset<Row> jdbcDF = spark.read()
.format("jdbc")
.option("url", "jdbc:postgresql:dbserver")
.option("dbtable", "schema.tablename")
.option("user", "username")
.option("password", "password")
.load(); Properties connectionProperties = new Properties();
connectionProperties.put("user", "username");
connectionProperties.put("password", "password");
Dataset<Row> jdbcDF2 = spark.read()
.jdbc("jdbc:postgresql:dbserver", "schema.tablename", connectionProperties); // Saving data to a JDBC source
jdbcDF.write()
.format("jdbc")
.option("url", "jdbc:postgresql:dbserver")
.option("dbtable", "schema.tablename")
.option("user", "username")
.option("password", "password")
.save(); jdbcDF2.write()
.jdbc("jdbc:postgresql:dbserver", "schema.tablename", connectionProperties); // Specifying create table column data types on write
jdbcDF.write()
.option("createTableColumnTypes", "name CHAR(64), comments VARCHAR(1024)")
.jdbc("jdbc:postgresql:dbserver", "schema.tablename", connectionProperties);

5.3Python

# Note: JDBC loading and saving can be achieved via either the load/save or jdbc methods
# Loading data from a JDBC source
jdbcDF = spark.read \
.format("jdbc") \
.option("url", "jdbc:postgresql:dbserver") \
.option("dbtable", "schema.tablename") \
.option("user", "username") \
.option("password", "password") \
.load() jdbcDF2 = spark.read \
.jdbc("jdbc:postgresql:dbserver", "schema.tablename",
properties={"user": "username", "password": "password"}) # Specifying dataframe column data types on read
jdbcDF3 = spark.read \
.format("jdbc") \
.option("url", "jdbc:postgresql:dbserver") \
.option("dbtable", "schema.tablename") \
.option("user", "username") \
.option("password", "password") \
.option("customSchema", "id DECIMAL(38, 0), name STRING") \
.load() # Saving data to a JDBC source
jdbcDF.write \
.format("jdbc") \
.option("url", "jdbc:postgresql:dbserver") \
.option("dbtable", "schema.tablename") \
.option("user", "username") \
.option("password", "password") \
.save() jdbcDF2.write \
.jdbc("jdbc:postgresql:dbserver", "schema.tablename",
properties={"user": "username", "password": "password"}) # Specifying create table column data types on write
jdbcDF.write \
.option("createTableColumnTypes", "name CHAR(64), comments VARCHAR(1024)") \
.jdbc("jdbc:postgresql:dbserver", "schema.tablename",
properties={"user": "username", "password": "password"})

Spark JDBC系列--取数的四种方式的更多相关文章

  1. JSP向后台传 递 参 数 的四种方式

    一.通过Form表单提交传值 客户端通过Form表单提交到服务器端,服务器端通过 Java代码 request.getParameter(String xx); 来取得参数(xx)为参数名称.通过ge ...

  2. 160624、Spark读取数据库(Mysql)的四种方式讲解

    目前Spark支持四种方式从数据库中读取数据,这里以Mysql为例进行介绍. 一.不指定查询条件 这个方式链接MySql的函数原型是: 1 def jdbc(url: String, table: S ...

  3. Excel VBA 从外部工作簿取数的5种方法

    '======================================================= '1.循环单元格取数,效率最低,不可取,初学者易犯 '2.区域相等取数 '3.复制粘贴 ...

  4. Spark入Hbase的四种方式效率对比

    一.方式介绍 本次测试一种采用了四种方式进行了对比,分别是:1.在RDD内部调用java API.2.调用saveAsNewAPIHadoopDataset()接口.3.saveAsHadoopDat ...

  5. EF5+MVC4系列(7) 后台SelectListItem传值给前台显示Select下拉框;后台Action接收浏览器传值的4种方式; 后台Action向前台View视图传递数据的四种方式(ViewDate,TempDate,ViewBag,Model (实际是ViewDate.Model传值))

    一:后台使用SelectListItem 传值给前台显示Select下拉框 我们先来看数据库的订单表,里面有3条订单,他们的用户id对应了 UserInfo用户表的数据,现在我们要做的是添加一个Ord ...

  6. iOS 登陆的实现四种方式

    iOS 登陆的实现四种方式 一. 网页加载: http://www.cnblogs.com/tekkaman/archive/2013/02/21/2920218.ht ml [iOS登陆的实现] A ...

  7. .net core 2.x - 缓存的四种方式

    其实这些微软docs都有现成的,但是现在的人想对浮躁些,去看的不会太多,所以这里就再记录下 ,大家一起懒一起浮躁,呵呵. 0.基础知识 通过减少生成内容所需的工作,缓存可以显著提高应用的性能和可伸缩性 ...

  8. C#批量插入数据到Sqlserver中的四种方式

    我的新书ASP.NET MVC企业级实战预计明年2月份出版,感谢大家关注! 本篇,我将来讲解一下在Sqlserver中批量插入数据. 先创建一个用来测试的数据库和表,为了让插入数据更快,表中主键采用的 ...

  9. C#_批量插入数据到Sqlserver中的四种方式

    先创建一个用来测试的数据库和表,为了让插入数据更快,表中主键采用的是GUID,表中没有创建任何索引.GUID必然是比自增长要快的,因为你生成一个GUID算法所花的时间肯定比你从数据表中重新查询上一条记 ...

随机推荐

  1. 8种常被忽视的SQL错误用法,你中招了吗?

    前言 MySQL在近几年仍然保持强劲的数据库流行度增长趋势.越来越多的客户将自己的应用建立在 MySQL 数据库之上,甚至是从 Oracle 迁移到 MySQL上来.但也存在部分客户在使用 MySQL ...

  2. 宿主机网络中其它机器与Docker容器网络互通配置

    前言 目前项目采用微服务架构进行开发,Nacos和其它服务部署到Docker中,Docker中容器采用的网络默认是桥接模式(Bridge),默认的子网码是172.17.0.1/16:宿主机是192.1 ...

  3. 表单绑定v-model

    表单控件在实际开发中是极为常见的.特别是对于用户信息的提交,需要大量的表单.Vue中使用v-model指令来实现表单元素和数据的双向绑定.此篇记录下其原理,以及当时学习时候的一些小尝试以及修饰符. v ...

  4. (转) MySQL常用Json函数

    原文:http://www.cnblogs.com/waterystone/p/5626098.html 官方文档:JSON Functions Name Description JSON_APPEN ...

  5. Alpha冲刺——汇总博客

    一.代码规范与计划 代码规范与计划 二.10篇冲刺随笔 冲刺随笔--Day1 冲刺随笔--Day2 冲刺随笔--Day3 冲刺随笔--Day4 冲刺随笔--Day5 冲刺随笔--Day6 冲刺随笔-- ...

  6. PO,BO,VO,DTO,POJO,DAO,DO是什么?

    PO (Persistent Object)   持久化对象,表示实体数据.BO (Business Object)        业务对象,主要是把逻辑业务封装为一个对象 .VO (Value/Vi ...

  7. 用python+sklearn(机器学习)实现天气预报数据 模型和使用

    用python+sklearn机器学习实现天气预报 模型和使用 项目地址 系列教程 0.前言 1.建立模型 a.准备 引入所需要的头文件 选择模型 选择评估方法 获取数据集 b.建立模型 c.获取模型 ...

  8. 【SpringBoot1.x】SpringBoot1.x 配置

    SpringBoot1.x 配置 文章源码 配置文件 SpringBoot 使用一个全局的配置文件,配置文件名是固定的. application.properties.application.yml都 ...

  9. Oracle数据库基础操作语法

    转载自:https://www.cnblogs.com/fallen-seraph/p/10685997.html 一.登录Oracle数据库 首先运行Oracle数据库: 默认的有两个账号: 管理员 ...

  10. MalformedByteSequenceException: 1字节的 UTF-8 序列的字节 1 无效

    记住,每次修改了配置之后都 clean 一下,把 target 删除 第一种解决方案 去掉 pom.xml 中的 properties <properties> <maven.com ...