
本文旨在解决使用pyspark将hadoop(hive)数据写入dbf文件时效率低下的问题。通过分析传统逐行写入和多线程尝试的局限性,我们揭示了类型转换和文件i/o是主要瓶颈。核心优化方案是利用`dbf`库的批量预分配和原地更新机制,显著提升写入性能。
在使用PySpark从Hadoop(Hive)中查询数据并将其保存到DBF文件时,开发者常会遇到写入速度远低于其他文件格式(如CSV、ORC)的问题,甚至可能耗时数十分钟。这种性能瓶颈主要源于以下两个核心原因:
以下是两种常见的、但效率不高的写入方式。它们都首先通过spark.sql(...).collect()将所有数据加载到Spark驱动程序的内存中,然后进行本地文件写入。
1. 逐行追加方式 (耗时约20分钟)
这种方法简单直观,但由于上述的类型转换和文件I/O问题,性能极差。
import dbf
from datetime import datetime
import os
# 假设collections已通过spark.sql().collect()获取,
# 且每个元素是Spark Row对象或类似字典的结构
# 例如:collections = spark.sql("SELECT JENISKEGIA, JUMLAHUM_A, ... FROM silastik.sakernas_2025_8").collect()
# 模拟数据,实际应为Spark DataFrame.collect()的结果
collections = [
{'JENISKEGIA': 1, 'JUMLAHUM_A': 100, 'URUTAN': 1, 'WEIGHT': 1.5},
{'JENISKEGIA': 2, 'JUMLAHUM_A': 200, 'URUTAN': 2, 'WEIGHT': 2.5},
# ... 更多数据
]
# 为了dbf.write兼容,Spark Row对象需要转换为字典
collections_as_dict = [row.asDict() if hasattr(row, 'asDict') else row for row in collections]
filename = f"/home/sak202508_{datetime.now().strftime('%Y%m%d%H%M%S')}_tes.dbf"
header = "JENISKEGIA N(8,0); JUMLAHUM_A N(8,0); URUTAN N(7,0); WEIGHT N(8,2)" # 示例header,请根据实际数据类型和精度调整
new_table = dbf.Table(filename, header)
new_table.open(dbf.READ_WRITE)
for row_data in collections_as_dict:
new_table.append(row_data) # 逐行追加,每次都可能触发文件元数据更新
new_table.close()
print(f"逐行追加方式写入完成: {filename}")2. 启用多线程尝试 (效果不明显)
芝士饼
芝士饼是一个一站式AI原生应用开发平台,简单几步即可完成应用的创建与发布。
84
查看详情
虽然引入多线程(concurrent.futures.ThreadPoolExecutor)看起来可以并行化写入操作,但在实际测试中,这种方法通常效果不佳。原因在于dbf库对文件的写入操作通常是串行化的,或者文件系统层面的锁机制会限制真正的并行写入。即使在多个线程中调用append(),底层的文件操作仍然可能被排队处理,无法有效利用多核优势。
import dbf
from datetime import datetime
import os
import concurrent.futures
# collections_as_dict 同上
collections_as_dict = [
{'JENISKEGIA': 1, 'JUMLAHUM_A': 100, 'URUTAN': 1, 'WEIGHT': 1.5},
{'JENISKEGIA': 2, 'JUMLAHUM_A': 200, 'URUTAN': 2, 'WEIGHT': 2.5},
# ... 更多数据
]
filename = f"/home/sak202508_{datetime.now().strftime('%Y%m%d%H%M%S')}_multithread_tes.dbf"
header = "JENISKEGIA N(8,0); JUMLAHUM_A N(8,0); URUTAN N(7,0); WEIGHT N(8,2)"
new_table = dbf.Table(filename, header)
new_table.open(dbf.READ_WRITE)
def append_row_task(table, record):
# 注意:此处的append可能仍然是线程安全的瓶颈
table.append(record)
# max_workers根据CPU核心数调整
max_workers = min(32, (os.cpu_count() or 1) + 4)
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
# 提交任务,但实际执行可能因dbf库内部机制而受限
futures = [executor.submit(append_row_task, new_table, row_data) for row_data in collections_as_dict]
# 等待所有任务完成
concurrent.futures.wait(futures)
new_table.close()
print(f"多线程方式写入完成: {filename}")针对上述瓶颈,dbf库提供了一种更高效的写入机制,即先批量预分配空行,然后通过迭代记录并使用dbf.write()进行原地更新。这种方法显著减少了文件I/O和元数据调整的次数,从而大幅提升性能。
import dbf
from datetime import datetime
import os
# 假设collections已通过spark.sql().collect()获取,
# 且每个元素是Spark Row对象或类似字典的结构
# 为了dbf.write兼容,Spark Row对象需要转换为字典
collections = [
{'JENISKEGIA': 1, 'JUMLAHUM_A': 100, 'URUTAN': 1, 'WEIGHT': 1.5},
{'JENISKEGIA': 2, 'JUMLAHUM_A': 200, 'URUTAN': 2, 'WEIGHT': 2.5},
{'JENISKEGIA': 3, 'JUMLAHUM_A': 300, 'URUTAN': 3, 'WEIGHT': 3.5},
{'JENISKEGIA': 4, 'JUMLAHUM_A': 400, 'URUTAN': 4, 'WEIGHT': 4.5},
{'JENISKEGIA': 5, 'JUMLAHUM_A': 500, 'URUTAN': 5, 'WEIGHT': 5.5},
# ... 更多数据
]
collections_as_dict = [row.asDict() if hasattr(row, 'asDict') else row for row in collections]
filename = f"/home/sak202508_{datetime.now().strftime('%Y%m%d%H%M%S')}_optimized_tes.dbf"
header = "JENISKEGIA N(8,0); JUMLAHUM_A N(8,0); URUTAN N(7,0); WEIGHT N(8,2)" # 示例header,请根据实际数据类型和精度调整
new_table = dbf.Table(filename, header)
new_table.open(dbf.READ_WRITE)
# 1. 批量预分配空行
number_of_rows = len(collections_as_dict)
if number_of_rows > 0:
new_table.append(multiple=number_of_rows)
# 2. 迭代记录并原地更新
# 注意:collections_as_dict中的每个元素必须是字典或能作为关键字参数传入dbf.write的映射
for rec, row_data in zip(new_table, collections_as_dict):
dbf.write(rec, **row_data) # 使用**row_data将字典解包为关键字参数
new_table.close()
print(f"优化方式写入完成: {filename}")将PySpark数据高效写入DBF文件,关键在于理解并规避dbf库在逐行操作时的性能瓶颈。通过采用批量预分配空行结合原地更新数据的策略,可以显著减少文件I/O和元数据调整的开销,从而将写入时间从数十分钟缩短到可接受的范围内。同时,开发者应始终关注collect()操作对驱动程序内存的影响,并根据数据集规模选择合适的处理策略。
以上就是PySpark大数据写入DBF文件性能优化指南的详细内容,更多请关注其它相关文章!
# 几种
# 东宝网站建设网站是什么
# 解放号媒体营销推广
# 西湖区全网营销推广
# 广告媒体推广营销模式
# 网站建设运营培训总结
# 阳江420seo-bk1066
# 外贸独立网站推广哪个好
# 舟山seo网络推广
# 企业要怎么做网站优化呢
# 江苏edm推广营销
# 迭代
# 多核
# 数十
# python
# 浮点
# 文件系统
# 是一个
# 芝士
# 转换为
# 多线程
# 性能瓶颈
# nas
# ai
# csv
# app
# 大数据
相关栏目:
【
Google疑问12 】
【
Facebook疑问10 】
【
优化推广96088 】
【
技术知识133117 】
【
IDC资讯59369 】
【
网络运营7196 】
【
IT资讯61894 】
相关推荐:
AffinityDesigner图层蒙版怎么用_AffinityDesigner图层蒙版设计应用
怎样让Windows 11的开始菜单恢复经典样式_Open-Shell工具使用指南【怀旧】
在PHP环境中正确加载HTML资源:CSS样式与图片路径指南
TikTok笔记文字无法编辑如何解决 TikTok笔记文字编辑优化方法
12306售票时间最新规定 | 网上订票和车站窗口时间一样吗
search中maxlength属性用法解析
Win11怎么设置分辨率 Win11显示设置调整分辨率及刷新率修改
《地下城堡4:骑士与破碎编年史》墓穴挑战125攻略
手机雨课堂网页版入口免登录 雨课堂网页版可点击直接进入
汽水音乐网页版登录 汽水音乐网页端官方入口
如何使用 Optional 类型并满足 Pylint 的类型检查
汽水音乐车机版官网5.0 汽水音乐车机版5.0版本下载入口
微信步数怎么刷_微信步数快速提升技巧
谷歌邮箱官方入口链接 谷歌邮箱网页版电脑端快速登录
Sublime Text怎么关闭自动完成_Sublime禁用Auto Complete设置
TikTok视频播放不流畅怎么办 TikTok视频播放优化方法
快手极速版在线体验区 快手极速版网页体验入口
Win10怎么设置快速启动 Win10开启快速启动设置方法
mysql数据库索引类型有哪些_mysql索引类型解析
Python实时数据流中高效查找最大最小值
狙击外星人小游戏在线链接_狙击外星人小游戏网页链接
小红书网页版在线直达 小红书网页版免费登录入口
圆通快递官方入口不需要登录 在线查询入口快速查询
在Peewee中处理PostgreSQL记录重复:一站式数据摄取教程
PHP页面重载时变量值不重置的实现方法
荣耀 Magic10 Pro 系统更新提示失败_荣耀 Magic10 Pro 升级修复
Flash AS3.0简易相册制作
Win10如何彻底关闭OneDrive Win10禁用云同步功能【纯净】
抖音视频如何添加标题?添加标题有哪些好处?
Excel如何制作月度销售统计图_Excel动态图表制作与控件应用
掌握Go App Engine项目结构与GOPATH:包管理与导入实践
怎样设置开机后自动运行某个程序_Windows启动文件夹与任务计划【自动化】
猫眼电影app如何参与官方的抽奖活动_猫眼电影官方抽奖参与方法
口腔诊所管理软件推荐
响应式设计中动态背景颜色条的实现指南
word怎么将图片设置为页面背景并不影响打印_Word图片背景设置方法
J*aScript二进制处理_ArrayBuffer与Blob
如何在CSS中设置背景图像:一个全面指南
win11怎么更改账户类型 Win11标准用户和管理员权限切换【教程】
Python中深度嵌套字典与列表的数据提取与条件过滤指南
稻壳阅读器官方直达网址链接 稻壳阅读器文档阅读平台主页资源入口
Golang如何初始化module项目_Golang module init使用说明
rabbitmq 持久化有什么缺点?
学习通网页版课程打不开_课程无法访问时的解决方法
Python中对象引用与链表属性赋值的机制解析
《雅迪智行》用手机开锁方法
英雄联盟争者留名活动介绍
PPT页面尺寸怎么修改 PPT自定义幻灯片大小与方向设置【教程】
微博网页版访问入口 微博网页版网页端使用指南
WPS长文档分栏排版不乱方法_WPS分栏+分节符报纸排版教程
2025-10-31
运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。