使用Databricks从ADLS向Azure SQL DB写入15GB数据时性能慢且超时
一、Databricks代码与集群优化
1. 改用COPY INTO替代JDBC批量写入
这是目前最有效的方式,Azure SQL原生支持COPY INTO批量加载外部存储的Parquet文件,比JDBC逐批插入效率高几个量级,还能减少连接开销。
先确保Azure SQL DB有权限访问ADLS(比如用托管身份配置权限),然后在Databricks中执行以下代码:
# 替换为你的存储账号、容器、Parquet路径和目标表名 storage_account = "your-storage-account" parquet_path = "path/to/daily-parquet" target_table = "your-target-table" copy_sql = f""" COPY INTO {target_table} FROM 'abfss://container@{storage_account}.dfs.core.windows.net/{parquet_path}' WITH ( FILE_FORMAT = 'PARQUET', COPY_OPTIONS = ('TRUNCATE_TABLE' = 'ON') ) """ spark.sql(copy_sql)
这个方式会直接让SQL DB拉取ADLS的Parquet数据,完全绕开JDBC的逐行/逐批传输瓶颈。
2. 优化JDBC写入参数(如果必须用JDBC)
如果业务依赖JDBC写入,调整以下参数解决超时和效率问题:
- 增加
numPartitions:匹配集群总核数设置为40,让多个分区并行写入,避免单分区拖慢整体速度 - 调小
batchsize:10万批次太大,改成5万-8万,减少单批次数据传输的超时概率 - 延长连接超时:在连接属性里添加超时参数,避免连接过早断开
修改后的代码:
source_df.write\ .mode("overwrite")\ .option("truncate", True)\ .option("tableLock", "false")\ .option("batchsize", "50000")\ .option("numPartitions", "40")\ .option("schemaCheckEnabled", "false")\ .option("connectTimeout", "300000")\ # 5分钟超时 .option("socketTimeout", "300000")\ .jdbc(jdbcUrl, target_table, properties=connection_properties)
另外提前对DataFrame做哈希分区,让每个分区数据量均匀:
source_df = source_df.repartition(40, "your-partition-column")
3. 集群资源优化
- 检查Spark UI的Executor指标,确认没有内存/CPU瓶颈,若有则调整Executor内存配置
- 开启动态资源分配,让集群根据任务自动调整Executor数量,避免资源闲置浪费
二、Azure SQL DB端优化
1. 临时扩容DTU
ETL时段临时升级到S16(4000DTU),完成加载后再降回S12,用临时的资源提升换加载速度,成本增加有限。
2. 禁用索引与约束再重建
写入前先禁用非聚集索引和外键约束,避免写入时的索引维护开销,完成后再重建:
-- 写入前执行 ALTER INDEX ALL ON [target_table] DISABLE; ALTER TABLE [target_table] NOCHECK CONSTRAINT ALL; -- 写入完成后执行 ALTER INDEX ALL ON [target_table] REBUILD; ALTER TABLE [target_table] CHECK CONSTRAINT ALL;
3. 改用聚集列存储索引
如果目标表是堆表或普通聚集索引表,改成聚集列存储索引(CCI),大表批量加载性能会大幅提升,后续查询效率也更高:
CREATE CLUSTERED COLUMNSTORE INDEX CCI_{target_table} ON [target_table];
4. 启用快照隔离
开启READ_COMMITTED_SNAPSHOT和ALLOW_SNAPSHOT_ISOLATION,减少写入时的锁竞争:
ALTER DATABASE [your-db-name] SET READ_COMMITTED_SNAPSHOT ON; ALTER DATABASE [your-db-name] SET ALLOW_SNAPSHOT_ISOLATION ON;
三、ADF结合方案
1. 直接用ADF Copy Activity加载
ADF原生支持从ADLS Parquet到Azure SQL DB的批量复制,默认用PolyBase或COPY INTO,效率比Databricks JDBC高。配置时设置并行复制数(建议和SQL DB的DTU匹配),启用“截断表”选项即可。
2. Databricks预处理+ADF加载
如果需要数据转换,先用Databricks把处理后的Parquet写入ADLS临时路径,再用ADF Copy Activity加载到SQL DB,避免Databricks直接连接SQL的开销。
内容的提问来源于stack exchange,提问作者Harish J

