我试图在单个节点(local [*])上以独立模式通过JDBC访问中型Teradata表(约1亿行)。
我正在使用Spark 1.4.1。并且安装在功能非常强大的机器上(2个CPU,24个内核,126G RAM)。
我尝试了几种内存设置和调整选项,以使其更快地工作,但它们都没有产生巨大的影响。
我确信有一些我缺少的东西,下面是我的最后一次尝试,花了大约11分钟来获得这个简单的计数与使用JDBC连接通过R只需要40秒来获取计数。
bin/pyspark --driver-memory 40g --executor-memory 40g
df = sqlContext.read.jdbc("jdbc:teradata://......)
df.count()
当我尝试使用BIG表(5B记录)时,在完成查询后没有返回任何结果。
答案 0 :(得分:14)
在将整个数据集检索到内存中的DataFrame
集合之后,执行所有聚合操作。因此,在Spark中进行计数永远不会像直接在TeraData中那样高效。有时,通过创建视图然后使用JDBC API映射这些视图,将一些计算推送到数据库中是值得的。
每次使用JDBC驱动程序访问大型表时,都应指定分区策略,否则您将使用单个分区创建DataFrame
/ RDD
,并且您将重载单个JDBC连接。
相反,您想尝试以下AI(自Spark 1.4.0 +以来):
sqlctx.read.jdbc(
url = "<URL>",
table = "<TABLE>",
columnName = "<INTEGRAL_COLUMN_TO_PARTITION>",
lowerBound = minValue,
upperBound = maxValue,
numPartitions = 20,
connectionProperties = new java.util.Properties()
)
还有一个选项可以按下一些过滤。
如果您没有统一分布的整数列,则需要通过指定自定义谓词(where
语句)来创建一些自定义分区。例如,假设您有一个时间戳列,并希望按日期范围进行分区:
val predicates =
Array(
"2015-06-20" -> "2015-06-30",
"2015-07-01" -> "2015-07-10",
"2015-07-11" -> "2015-07-20",
"2015-07-21" -> "2015-07-31"
)
.map {
case (start, end) =>
s"cast(DAT_TME as date) >= date '$start' AND cast(DAT_TME as date) <= date '$end'"
}
predicates.foreach(println)
// Below is the result of how predicates were formed
//cast(DAT_TME as date) >= date '2015-06-20' AND cast(DAT_TME as date) <= date '2015-06-30'
//cast(DAT_TME as date) >= date '2015-07-01' AND cast(DAT_TME as date) <= date '2015-07-10'
//cast(DAT_TME as date) >= date '2015-07-11' AND cast(DAT_TME as date) <= date //'2015-07-20'
//cast(DAT_TME as date) >= date '2015-07-21' AND cast(DAT_TME as date) <= date '2015-07-31'
sqlctx.read.jdbc(
url = "<URL>",
table = "<TABLE>",
predicates = predicates,
connectionProperties = new java.util.Properties()
)
它将生成一个DataFrame
,其中每个分区将包含与不同谓词关联的每个子查询的记录。
答案 1 :(得分:0)
一种不同于其他解决方案的解决方案是将来自oracle表的数据保存在hadoop上保存的avro文件中(分为许多文件)。 这样一来,用spark读取那些avro文件将是一件轻松的事,因为您将不再调用db。