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

24 投票
2 回答
23939 浏览
提问于 2025-04-18 08:22

我正在使用Pandas的to_sql函数把数据写入MySQL,但因为数据量太大(有100万行,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)

2 个回答

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函数中切片第二个索引。

31

更新:这个功能已经合并到pandas的主版本中,并将在0.15版本中发布(大概在九月底),感谢@artemyk!详情请见 这里

所以从0.15版本开始,你可以指定 chunksize 参数,比如说可以简单地这样做:

df.to_sql('table', engine, chunksize=20000)

撰写回答