之前遇到一个需求,使用spark计算完成之后,df有将近百万数据需要写入到MySQL中
日方写法:
mysql_driver = "com.mysql.jdbc.Driver"
mysql_url = "jdbc:mysql://localhost:3306/my_test_db"
dataframe.write.mode('append').format("jdbc").options(url=mysql_url,driver=mysql_driver,usr="test",password="xxxxx",dbtable="test_demo").save()
此种写法,如果处理小数据量可以达到秒插入。如果插入数据量比较大,则会很慢
然后就去spark官网,在spark sql jdbc部分看到了以下参数
url:要连接的JDBC URL。列如:jdbc:mysql://ip:3306
dbtable:应该读取的JDBC表。可以使用括号中的子查询代替完整表(使用select 语句代替表,例如,(select * from table_name) as t1,必须给查询结果加上别名)
driver:用于连接到此URL的JDBC驱动程序的类名,列如:com.mysql.jdbc.Driver
partitionColumn,
lowerBound,
upperBound,
numPartitions:这些options仅适用于read数据。这些options必须同时被指定。他们描述,如何从多个workers并行读取数据时,分割表。partitionColumn必须是表中的数字列。lowerBound和upperBound仅用于决定分区的大小,而不是用于过滤表中的行。表中的所有行将被分割并返回。
fetchsize:仅适用于read数据。JDBC提取大小,用于确定每次获取的行数。这可以帮助JDBC驱动程序调优性能,这些驱动程序默认具有较低的提取大小(例如,Oracle每次提取10行)。
batchsize:仅适用于write数据。JDBC批量大小,用于确定每次insert的行数。这可以帮助JDBC驱动程序调优性能。默认为1000。
isolationLevel:仅适用于write数据。事务隔离级别,适用于当前连接。它可以是一个NONE,READ_COMMITTED,READ_UNCOMMITTED,REPEATABLE_READ,或SERIALIZABLE,对应于由JDBC的连接对象定义,缺省值为标准事务隔离级别READ_UNCOMMITTED。
truncate:仅适用于write数据。当SaveMode.Overwrite启用时,此选项会truncate在MySQL中的表,而不是删除,再重建其现有的表。这可以更有效,并且防止表元数据(例如,索引)被去除。但是,在某些情况下,例如当新数据具有不同的模式时,它将无法工作。它默认为false。
createTableOptions:仅适用于write数据。此选项允许在创建表(例如CREATE TABLE t (name string) ENGINE=InnoDB.)时设置特定的数据库表和分区选项。
这时,修改后的代码为
dataframe.write.mode('overwrite').format("jdbc").options(
url=mysql_url+"?rewriteBatchedStatements=true", # 开启批处理
driver=mysql_driver,
user='test',
password='xxxxxx',
dbtable=save_table_name,
batchsize=10000, # 每批数据大小
isolationLevel='NONE', # 事务隔离,这里不需要做事务隔离
truncate='true' # 如果不加次参数,overwrite则是删除表重新创建,加上则时trunacte 表而不删除
).save()
此时效率提升很多,减少等待时间