通过Spark SQL批量迁移数据

时间:2016-08-19 18:13:10

标签: apache-spark apache-spark-sql spark-dataframe

我目前正尝试通过Spark SQL将非常大的MySQL表的内容批量迁移到镶木地板文件中。但是当这样做时,即使将驱动程序的内存限制设置得更高(我在本地模式下使用spark),我也会很快耗尽内存。示例代码:

Dataset<Row> ds = spark.read()
    .format("jdbc")
    .option("url", url)
    .option("driver", "com.mysql.jdbc.Driver")
    .option("dbtable", "bigdatatable")
    .option("user", "root")
    .option("password", "foobar")
    .load();

ds.write().mode(SaveMode.Append).parquet("data/bigdatatable");

似乎Spark试图将整个表格内容读入内存,但这并不能很好地解决问题。那么,通过Spark SQL进行批量数据迁移的最佳方法是什么?

1 个答案:

答案 0 :(得分:5)

在您的解决方案中,Spark会在开始编写之前将整个表内容读入一个分区。您可以避免的一种方法是对读取部分进行分区,但它需要源数据中的数字顺序列:

Dataset<Row> ds = spark.read()
  .format("jdbc")
  .option("url", url)
  .option("driver", "com.mysql.jdbc.Driver")
  .option("dbtable", "bigdatatable")
  .option("user", "root")
  .option("password", "foobar")
  .option("partitionColumn", "NUMERIC_COL")
  .option("lowerBound", "1")
  .option("upperBound", "10000")
  .option("numPartitions", "64")
  .load();

在上面的例子中,数据中必须存在“NUMERIC_COL”列,理想情况下,它应该从1到10000统一变化。当然,这是很多要求,而且这样的列可能不存在,所以你应该用这样的列在数据库中创建一个视图,或者在查询中添加它(注意我使用了通用的SQL语法,你必须适应你的DBMS):

String query = "(select mod(row_number(), 64) as NUMERIC_COL, * from bigdatatable) as foo"

Dataset<Row> ds = spark.read()
  .format("jdbc")
  .option("url", url)
  .option("driver", "com.mysql.jdbc.Driver")
  .option("dbtable", query)
  .option("user", "root")
  .option("password", "foobar")
  .option("partitionColumn", "NUMERIC_COL")
  .option("lowerBound", "0")
  .option("upperBound", "63")
  .option("numPartitions", "64")
  .load();