【问题标题】:Large Dask/Pandas DataFrame (27M rows x 52 columns) .to_csv or .to_sql MemoryError大型 Dask/Pandas 数据帧(27M 行 x 52 列).to_csv 或 .to_sql MemoryError
【发布时间】:2020-06-12 07:45:07
【问题描述】:

长话短说,我一直在努力解决内存问题(以及执行时间)dask/pandas 写一个大数据框to_sqlto_csv 如果有人能指出我的正确之处方向(下面更详细)?

为了节省内存而不是使用 pandas,我将两个大的 .csv 文件附加在一起以形成一个更大的 .csv 文件(27M 行 x 52 列)dask,因为我的内存不足或接近它。

从那里,我只是尝试写入.csv,但我再次耗尽内存尝试使用.compute() 从dask 数据帧转换为pandas 数据帧并写入文件。我想把这个问题集中在如何简单地将这个东西放入 .csv 而不会耗尽内存。从那里,我计划使用 SQL Server 的导入向导将文件导入数据库中的新表。请参阅下面的代码,了解我是如何阅读的,concat'ing 作为 dask 数据帧,转换为 pandas 数据帧,然后在内存不足之前尝试写入 .csv:

df1 = dd.read_csv('C:/Users/david.erickson/file1.csv', dtype={'Phone #': str, 'Called #': str})
df2 = dd.read_csv('C:/Users/david.erickson/file2.csv', dtype={'Phone #': str, 'Called #': str})
df_combined = dd.concat([df1,df2], axis=0).drop_duplicates()
df_combined = df_combined.compute()
df_combined.to_csv('C:/Users/david.erickson/file_combined.csv', index=False)

在观看 python 接近 38 GB 的已提交物理内存后,我在第四行或第五行遇到内存错误:

MemoryError: Unable to allocate 210. MiB for an array with shape (27571126,) and data type int64

在任何人提到它之前,我也不知疲倦地尝试了to_sql 以及没有成功,因为最终目标是将这些数据放入 SQL Sever 数据库中。它一直持续下去,我遇到了sqlalchemyto_sql 的内存错误。更好的是,我希望我可以直接写入 SQL Server,我尝试过的是:

engine = sa.create_engine(cnxn_string, fast_executemany=True)
connection = engine.connect()
df.to_sql('New_Table', con=engine, if_exists='replace', index=False) 

我也试过了:df6.to_sql('New_Table', con=engine, if_exists='replace', index=False, chunksize=40, method='multi') #有2098个参数的限制,这就是为什么chunksize=40(40*52列=2080,所以小于限制。反正这比只传@987654341慢@到create_engine)

不幸的是,上述尝试以及我用.to_sql 研究的其他一些python sqlalchemy 方法只是内存不足或操作需要很长时间(一夜之间),我不得不杀死它。

在 52 列和 2750 万行中,我猜每个单元格的平均字符串大小约为 20 个字符(至少对于文本列而言)。我必须做一些不同的事情才能将这些数据导入 SQL Server 数据库,但我真的很挣扎,在这个项目之前,我从来没有遇到过 to_sqlto_csv 的问题。

【问题讨论】:

  • 不幸的是,我现在是 0 比 3。我只是尝试通过 singlefile=True 的完整代码行:df_combined.to_csv('C:/Users/david.erickson/file_combined.csv', index=False, single_file=True) 并收到相同的错误:MemoryError: Unable to allocate 210. MiB for an array with shape (27571126,) and data type int64
  • 我使用了一个新的虚拟机和 10 倍内存,我能够合并文件。它最终占用了大约 50 GB 的内存和上面评论中的代码。我现在成功(希望)使用导入数据向导将合并的 14.7 GB 文件读入 SQL Server。

标签: python sql-server pandas dask pandas-to-sql


【解决方案1】:

假设 CSV 有类似主键的东西,拆分数据集。如果您有 52 列,请将其拆分为 4 帧和 14 列(每列 4x 13,并复制主键列以便匹配它们),然后将较小的数据集传递给 SQL。

或者做一个主键列表,只插入前N个,提交事务,然后开始下一批。

此外,MS SQL 有一个用于 .csv 的导入功能,由于它批量插入,因此效率相当高。为什么要用python作为两者之间的层?

【讨论】:

  • 我尝试只导入一个文件,但我遇到了其中一列的格式错误,只是将列设为 varchar(500),以防有些行有一个长字符串(它不会告诉您哪一列有问题数据)。这显然有帮助,但后来我遇到了一些日期列的格式问题,导入卡住了,之后我没有尝试。关于使用 SQL Server 的工具导入 SQL 表的话题,我不确定如何将两个文件导入到一个表中,所以我试图创建一个大文件,然后再试一次。
  • 您可以通过执行 2 个连续的导入作业将它们导入到同一个表中。假设列名和顺序匹配,这应该不是问题。如果它们不匹配,或者只是让您在合并之前获得源表,您也可以将它们导入单独的表,然后使用常规 SQL 合并 2(使用循环进行批处理)请记住在执行此操作之前从目标表中删除所有索引.索引非常适合搜索,不适用于批量插入。事后重建它们的速度更快,然后在启用它们的情况下插入
  • 感谢您的 cmets。根据对我的回答的评论,我能够让它工作。对于我的问题的下一部分,我可能会发布一个单独的问题,但我希望让一些有 python/sqlalchemy/sqlserver 经验的人在接受任何答案之前发表一些见解。
猜你喜欢
  • 2017-04-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-04
  • 2014-07-23
  • 2019-12-21
  • 2020-02-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多