为什么我会在一个微小的df上使用fast_executemany获得内存错误?

Mar*_*bak 6 python sql-server sqlalchemy pyodbc pandas

我一直在寻找方法来加速将数据帧推送到sql server,并在这里偶然发现了一种方法.这种方法在速度方面让我感到震惊.使用normal to_sql需要将近2个小时,此脚本在12.54秒内完成,以推动100k行X 100列df.

因此,在使用示例df测试下面的代码之后,我尝试使用具有许多不同数据类型的df(int,string,float,Booleans).但是,我很遗憾看到内存错误.所以我开始减小我的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)
Run Code Online (Sandbox Code Playgroud)

Gor*_*son 12

我能够使用pyodbc 4.0.23重现您的问题.这MemoryError与你对古代的使用有关

DRIVER={SQL Server}
Run Code Online (Sandbox Code Playgroud)

进一步测试使用

DRIVER=ODBC Driver 11 for SQL Server
Run Code Online (Sandbox Code Playgroud)

也失败了

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

这与GitHub上现有的pyodbc问题有关.我在这里发布了我的发现.

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

  • 使用更新的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 并更改那里的数据类型,以防有人遇到同样的错误。 (2认同)