Python Pandas - 使用 to_sql 分块写入大型数据框

24

我正在使用Pandas的to_sql函数写入MySQL,但由于数据帧过大(1百万行,20列),导致出现了超时问题。

http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.to_sql.html

是否有更官方的方式来分块处理数据,并以块的形式写入行? 我已经编写了自己的代码,看起来可以工作。 不过我更倾向于一个官方的解决方案。 谢谢!

def write_to_db(engine, frame, table_name, chunk_size):

    start_index = 0
    end_index = chunk_size if chunk_size < len(frame) else len(frame)

    frame = frame.where(pd.notnull(frame), None)
    if_exists_param = 'replace'

    while start_index != end_index:
        print "Writing rows %s through %s" % (start_index, end_index)
        frame.iloc[start_index:end_index, :].to_sql(con=engine, name=table_name, if_exists=if_exists_param)
        if_exists_param = 'append'

        start_index = min(start_index + chunk_size, len(frame))
        end_index = min(end_index + chunk_size, len(frame))

engine = sqlalchemy.create_engine('mysql://...') #database details omited
write_to_db(engine, frame, 'retail_pendingcustomers', 20000)

就我所知,我不得不做这件确切的事情。 - Paul H
4
目前没有官方的解决方案,但我们非常欢迎补丁来实现这一点(有关 read_sql 的 chunksize 问题有一个 issue(https://github.com/pydata/pandas/issues/2908),您可以随时为此打开一个新的 issue)。 - joris
我创建了一个问题。@joris- 如果您不介意,请在那里添加一条评论并支持我:). https://github.com/pydata/pandas/issues/7347 - Krishan Gupta
为什么不将数据导出为csv文件(必须是表格格式),然后使用load data infile命令呢? - chuse
3个回答

31
更新:此功能已合并到pandas主分支中,并将在0.15版中发布(可能在9月底),感谢@artemyk!请参见https://github.com/pydata/pandas/pull/8062 因此,从0.15开始,您可以指定chunksize参数,例如只需执行以下操作:
df.to_sql('table', engine, chunksize=20000)

完美,它救了我的一天! - EntzY

1

针对这个问题,有许多优美的惯用函数块可供使用。

在您的情况下,您可以像这样使用此函数:

def chunks(l, n):
""" Yield successive n-sized chunks from l.
"""
    for i in xrange(0, len(l), n):
         yield l.iloc[i:i+n]

def write_to_db(engine, frame, table_name, chunk_size):
    for idx, chunk in enumerate(chunks(frame, chunk_size)):
        if idx == 0:
            if_exists_param = 'replace':
        else:
            if_exists_param = 'append'
        chunk.to_sql(con=engine, name=table_name, if_exists=if_exists_param)

唯一的缺点是 iloc 函数不支持对第二个索引进行切片。


0

从一个表中读取数据并分块写入另一个表...

[myconn1 ---> 源表],[myconn2----> 目标表],[ch= 10000]

for chunk in pd.read_sql_table(table_name=source, con=myconn1, chunksize=ch):
    chunk.to_sql(name=target, con=myconn2, if_exists="replace", index=False,
                 chunksize=ch)
    LOGGER.info(f"Done 1 chunk")

由于“replace”的存在,只有最后一块将持续存在:“插入新值之前删除表。” - Michel de Ruiter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接