【问题标题】:Why would I get a memory error with fast_executemany on a tiny df?为什么我会在一个很小的 ​​df 上使用 fast_executemany 出现内存错误?
【发布时间】:2018-09-27 23:42:45
【问题描述】:

我一直在寻找加快将数据帧推送到 sql server 的方法,偶然发现了一种方法 here. 这种方法在速度方面让我大吃一惊。使用普通的to_sql 花了将近 2 个小时,这个脚本在 12.54 秒内完成,以推送 100k 行 X 100 列 df。

因此,在使用示例 df 测试下面的代码后,我尝试使用具有许多不同数据类型(int、string、floats、Booleans)的 df。但是,看到内存错误,我很难过。所以我开始减小我的 df 的大小,看看有什么限制。我注意到如果我的 df 有任何字符串,那么我无法加载到 sql server。我无法进一步隔离问题。下面的脚本取自链接中的问题,但是,我添加了一个带有字符串的小 df。任何有关如何纠正此问题的建议都会很棒!

import pandas as pd
import numpy as np
import time
from sqlalchemy import create_engine, event
from urllib.parse import quote_plus
import pyodbc

conn =  "DRIVER={SQL Server};SERVER=SERVER_IP;DATABASE=DB_NAME;UID=USER_ID;PWD=PWD"
quoted = quote_plus(conn)
new_con = 'mssql+pyodbc:///?odbc_connect={}'.format(quoted)
engine = create_engine(new_con)


@event.listens_for(engine, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
    print("FUNC call")
    if executemany:
        cursor.fast_executemany = True


table_name = 'fast_executemany_test'
df1 = pd.DataFrame({'col1':['tyrefdg','ertyreg','efdgfdg'],
                   'col2':['tydfggfdgrefdg','erdfgfdgfdgfdgtyreg','edfgfdgdfgdffdgfdg']
                   })



s = time.time()
df1.to_sql(table_name, engine, if_exists = 'replace', chunksize = None)
print(time.time() - s)

【问题讨论】:

    标签: python sql-server pandas sqlalchemy pyodbc


    【解决方案1】:

    我能够使用 pyodbc 4.0.23 重现您的问题。 MemoryError 与您使用古代有关

    DRIVER={SQL Server}
    

    使用

    进一步测试
    DRIVER=ODBC Driver 11 for SQL Server
    

    也失败了,有

    函数序列错误 (0) (SQLParamData)

    这与 GitHub 上现有的 pyodbc 问题有关。我发布了我的发现here

    该问题仍在调查中。在此期间,您也许可以继续

    • 使用较新的 ODBC 驱动程序,例如 DRIVER=ODBC Driver 13 for SQL Server
    • 运行 pip install pyodbc==4.0.22 以使用早期版本的 pyodbc。

    【讨论】:

    • 谢谢! pyodbc 4.0.22 对我不起作用,但 pyodbc 4.0.19 工作正常。另外,我注意到在将数据类型添加到 to_sql 语句时脚本会引发错误。所以我只是将数据加载到 SQL Server 并在那里更改数据类型,以防有人遇到同样的错误。
    • 谢谢@MartinBobak 这是一个奇怪的错误..!我不得不摆弄元数据,它起作用了,但很烦人。还发现性能提升惊人。
    【解决方案2】:

    我也遇到过这个问题。

    通过改变解决:

    conn =  "DRIVER={SQL Server};SERVER=SERVER_IP;DATABASE=DB_NAME;UID=USER_ID;PWD=PWD"
    

    到这里:

    conn =  "DRIVER={ODBC Driver 17 for SQL Server};SERVER=SERVER_IP;DATABASE=DB_NAME;UID=USER_ID;PWD=PWD"
    

    【讨论】:

      【解决方案3】:

      我在 32 位时遇到了这个问题,并将我的中断器切换到 64 位,这解决了我的内存问题。在该解决方案之外,我建议将您处理的数据量分块。您可以建立您的阈值,一旦达到该阈值,您就可以处理该数据块并进行迭代,直到您处理完所有数据。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-06-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-04
        • 1970-01-01
        相关资源
        最近更新 更多