spark 数据读取关系型数据库或写入到关系型数据库问题
spark读取关系型数据库大表jdbc OOM
除非获取大小设置为Integer.MIN_VALUE ,否则JDBC驱动程序总是获取所有行.
默认情况下,ResultSets被完全检索并存储在内存中。 在大多数情况下,这是最有效的操作方式,并且由于MySQL网络协议的设计更容易实现。 如果您正在使用具有大量行或大值的ResultSets,并且无法在您的JVM中为需要的内存分配堆空间,那么您可以告诉驱动程序一次将结果串流回一行。
要启用此功能,请按以下方式创建一个Statement实例:
stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
java.sql.ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);
stmt.setFetchDirection(ResultSet.FETCH_REVERSE)
使用sparkSession的jdbcRead参数不能使用properties.put("fetchsize", Integer.MIN_VALUE), 需要拓展spark JDBCRDD类compute方法。
//代码片段
val myWhereClause = getWhereClause(part, options)
val sqlText = s"SELECT $columnList FROM ${options.table} $myWhereClause"
stmt = conn.prepareStatement(sqlText,
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)
//MYSQL 大表抽取问题 gbase也适用
if (url.contains("mysql") || url.contains("gbase")) {
stmt.setFetchSize(Integer.MIN_VALUE)
stmt.setFetchDirection(ResultSet.FETCH_REVERSE)
}else {
stmt.setFetchSize(options.fetchSize)
}
rs = stmt.executeQuery()
val rowsIterator = JdbcUtils.resultSetToSparkInternalRows(rs, schema, inputMetrics)
spark 数据写入关系型数据库慢
jdbc 默认使用循环提交数据的方法 executeBatch() 在jdbc url中添加配置rewriteBatchedStatements=true 使用批量提交数据
spark读取mysql时间格式转换出错
mysql中时间出现'0000-00-00 00:00:00'可能出现错误, 在jdbc url中添加配置 zeroDateTimeBehavior=convertToNul
zeroDateTimeBehavior
- ception:默认值,即抛出SQL state [S1009]. Cannot convert value....的异常;
- convertToNull:将日期转换成NULL值;
- round:替换成最近的日期即0001-01-01;
spark读取MPP库数据,使用limit分片 数据丢失或重复问题
MPP类型的数据库在使用集群模式时,每次数据查询结果顺序不同,使用limit分割数据并行读取会数据重复或丢失。
可以使用全字段排序或主键排序后再分割,并行抽取就不会出现数据丢失
读取MPP数据库大量表和大量数据时,不推荐使用partitionColumn, lowerBound, upperBound参数,这样需要适配每张表,总会遇到数据倾斜的现象。
可以通过 dbtable 构造子查询,使用特点的分割字段,如rowid,rownum,segment_id或limit等分割,不同数据库选择适配不同的通用分割方法。

浙公网安备 33010602011771号