我有一个非常大的
Pandas
数据框,大约有900万条记录,56列,我正在尝试使用Dataframe.to_sql()
将其加载到MSSQL表中。在一条语句中导入整个 Dataframe 通常会导致与内存相关的错误。
为了解决这个问题,我以 100K 行为一批循环遍历 Dataframe,并一次导入一批。这样我就不再遇到任何错误,但在大约 580 万条记录后,代码速度显着减慢。我正在使用的代码:
maxrow = df.shape[0]
stepsize = 100000
for i in range(0, maxrow, stepsize):
batchstart = datetime.datetime.now()
if i == 0:
if_exists = 'replace'
else:
if_exists = 'append'
df_import = df.iloc[i:i+stepsize]
df_import.to_sql('tablename',
engine,
schema='tmp',
if_exists=if_exists,
index=False,
dtype=dtypes
)
我已经对批次进行了计时,速度上有一个明显的断点: 对于 50k、100k 和 200k 行的批次,这些结果基本相同。上传 600 万条记录大约需要 40 分钟,上传接下来的 300 万条记录需要 2 小时 20 分钟。
我的想法是,这要么是由于 MSSQL 表的大小,要么是由于每次上传后缓存/保存的内容所致。因此,我尝试将数据框推送到两个不同的表。每次上传后,我还在
expunge_all()
上尝试过类似 SQLALchemy session
的操作。两者都没有效果。
在 500 万条记录后手动停止导入并使用新的引擎对象从 500 万条记录重新启动也没有帮助。
我完全不知道导致该过程如此急剧减慢的原因是什么,并且非常感谢您的帮助。
更新
作为最后的手段,我反转了循环,从最高索引开始上传部分数据帧,然后向下循环。
这基本上扭转了每批次的时间。所以看起来数据本身在数据帧中是不同/更大的。不是连接过载或 SQL 表变大。
感谢大家的帮助,但看来我需要查看数据来看看是什么原因造成的。
我找到了一个解决方案,对于其他希望加快缓慢(ing)
Dataframe.to_sql()
操作的人来说可能很有用,并且已经尝试过类似chunksizes
之类的方法并设置SQLALchemy
与fast_executemany=True
的连接
.
不确定是什么机制导致了这种性能变化,但它对我有用,而且我没有在其他地方看到它被提及。所以我希望它对其他人有帮助。
使用
DataFrame.sort_values()
对原始 Dataframe 进行排序已将所需时间减少了大约 2/3。
值在哪些列上排序似乎非常重要。当 Dataframe 按唯一的列排序并且行为类似于嵌套/聚集排序时,速度是最好的。按此列排序隐式按约 20 列排序。
它对地址进行排序,同时对街道、邮政编码、城市、地区等进行排序。这也意味着批次中的许多行共享行中的许多值。当 Dataframe 按与其他列没有连接的另一列排序时,它实际上会显着减慢
Dataframe.to_sql()
速度。