pyodbc/sqlAchemy 启用快速执行多个
pyodbc/sqlAchemy enable fast execute many
@IljaEverilä 回答我的问题 How to speed up data wrangling A LOT in Python + Pandas + sqlAlchemy + MSSQL/T-SQL I was kindly directed to 。
NB 出于测试目的,我只有 reading/writing 10k 行。
我添加了事件侦听器并且 a) 函数被调用但是 b) 很明显 executemany 没有设置,因为 IF 失败并且 cursor.fast_executemay 没有设置。
def namedDbSqlAEngineCreate(dbName):
# Create an engine and switch to the named db
# returns the engine if successful and None if not
# 2018-08-23 added fast_executemany accoding to this
engineStr = 'mssql+pyodbc://@' + defaultDSN
engine = sqla.create_engine(engineStr, echo=False)
@event.listens_for(engine, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
# print("FUNC call")
if executemany:
print('executemany')
cursor.fast_executemany = True
try:
engine.execute('USE ' +dbName)
return(engine)
except sqla.exc.SQLAlchemyError as ex:
if ex.orig.args[0] == '08004':
print('namedDbSqlAEngineCreate:Database %s does not exist' % dbName)
else:
print(ex.args[0])
return(None)
速度自然没有变化
我原问题中的代码在to_sql
中没有改变
nasToFillDF.to_sql(name=tempTableName, con=engine.engine, if_exists='replace', chunksize=100, index=False)
因为我尝试按照示例设置 chunksize = None 并收到错误消息(我之前遇到过)
(pyodbc.ProgrammingError) ('The SQL contains -31072 parameter markers,
but 100000 parameters were supplied', 'HY000')
我做错了什么?我想 receive_before_cursor_execute 的 executemany 参数没有设置,但如果这是答案,我不知道如何修复它。
安装程序是 pyodbc 4.0.23,sqlAchemy 1.2.6,Python 3.6.something
您收到的错误是由 Pandas 版本 0.23.0 中引入的更改引起的,在 0.23.1 中还原,并在 0.24.0 中重新引入,如 所述。生成的 VALUES 子句包含 100,000 个参数标记,而且计数似乎存储在一个带符号的 16 位整数中,所以它溢出了,你得到了有趣的
The SQL contains -31072 parameter markers, but 100000 parameters were supplied
你可以自己查一下:
In [16]: 100000 % (2 ** 16) - 2 ** 16
Out[16]: -31072
如果您想继续按原样使用 Pandas,您必须计算并提供合适的 chunksize
值,例如您使用的 100,同时考虑到VALUES 子句的最大行限制为 1,000,存储过程的最大参数限制为 2,100。详细信息在 .
中再次说明
更改 Pandas 之前总是使用 executemany()
when inserting data. Newer versions detect if the dialect in use supports VALUES clause in INSERT. This detection happens in SQLTable.insert_statement()
and cannot be controlled, which is a shame since PyODBC fixed their executemany()
performance, 。
为了强制 Pandas 再次使用 PyODBC executemany()
SQLTable
必须是 monkeypatched:
import pandas.io.sql
def insert_statement(self, data, conn):
return self.table.insert(), data
pandas.io.sql.SQLTable.insert_statement = insert_statement
如果未设置 Cursor.fast_executemany
标志,这将可怕地 缓慢,因此请记住设置正确的事件处理程序。
这是一个简单的性能比较,使用以下数据帧:
In [12]: df = pd.DataFrame({f'X{i}': range(1000000) for i in range(9)})
香草 Pandas 0.24.0:
In [14]: %time df.to_sql('foo', engine, chunksize=209)
CPU times: user 2min 9s, sys: 2.16 s, total: 2min 11s
Wall time: 2min 26s
Monkeypatched Pandas 启用快速执行:
In [10]: %time df.to_sql('foo', engine, chunksize=500000)
CPU times: user 12.2 s, sys: 981 ms, total: 13.2 s
Wall time: 38 s
@IljaEverilä 回答我的问题 How to speed up data wrangling A LOT in Python + Pandas + sqlAlchemy + MSSQL/T-SQL I was kindly directed to
NB 出于测试目的,我只有 reading/writing 10k 行。
我添加了事件侦听器并且 a) 函数被调用但是 b) 很明显 executemany 没有设置,因为 IF 失败并且 cursor.fast_executemay 没有设置。
def namedDbSqlAEngineCreate(dbName):
# Create an engine and switch to the named db
# returns the engine if successful and None if not
# 2018-08-23 added fast_executemany accoding to this
engineStr = 'mssql+pyodbc://@' + defaultDSN
engine = sqla.create_engine(engineStr, echo=False)
@event.listens_for(engine, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
# print("FUNC call")
if executemany:
print('executemany')
cursor.fast_executemany = True
try:
engine.execute('USE ' +dbName)
return(engine)
except sqla.exc.SQLAlchemyError as ex:
if ex.orig.args[0] == '08004':
print('namedDbSqlAEngineCreate:Database %s does not exist' % dbName)
else:
print(ex.args[0])
return(None)
速度自然没有变化
我原问题中的代码在to_sql
中没有改变nasToFillDF.to_sql(name=tempTableName, con=engine.engine, if_exists='replace', chunksize=100, index=False)
因为我尝试按照示例设置 chunksize = None 并收到错误消息(我之前遇到过)
(pyodbc.ProgrammingError) ('The SQL contains -31072 parameter markers, but 100000 parameters were supplied', 'HY000')
我做错了什么?我想 receive_before_cursor_execute 的 executemany 参数没有设置,但如果这是答案,我不知道如何修复它。
安装程序是 pyodbc 4.0.23,sqlAchemy 1.2.6,Python 3.6.something
您收到的错误是由 Pandas 版本 0.23.0 中引入的更改引起的,在 0.23.1 中还原,并在 0.24.0 中重新引入,如
The SQL contains -31072 parameter markers, but 100000 parameters were supplied
你可以自己查一下:
In [16]: 100000 % (2 ** 16) - 2 ** 16
Out[16]: -31072
如果您想继续按原样使用 Pandas,您必须计算并提供合适的 chunksize
值,例如您使用的 100,同时考虑到VALUES 子句的最大行限制为 1,000,存储过程的最大参数限制为 2,100。详细信息在
更改 Pandas 之前总是使用 executemany()
when inserting data. Newer versions detect if the dialect in use supports VALUES clause in INSERT. This detection happens in SQLTable.insert_statement()
and cannot be controlled, which is a shame since PyODBC fixed their executemany()
performance,
为了强制 Pandas 再次使用 PyODBC executemany()
SQLTable
必须是 monkeypatched:
import pandas.io.sql
def insert_statement(self, data, conn):
return self.table.insert(), data
pandas.io.sql.SQLTable.insert_statement = insert_statement
如果未设置 Cursor.fast_executemany
标志,这将可怕地 缓慢,因此请记住设置正确的事件处理程序。
这是一个简单的性能比较,使用以下数据帧:
In [12]: df = pd.DataFrame({f'X{i}': range(1000000) for i in range(9)})
香草 Pandas 0.24.0:
In [14]: %time df.to_sql('foo', engine, chunksize=209)
CPU times: user 2min 9s, sys: 2.16 s, total: 2min 11s
Wall time: 2min 26s
Monkeypatched Pandas 启用快速执行:
In [10]: %time df.to_sql('foo', engine, chunksize=500000)
CPU times: user 12.2 s, sys: 981 ms, total: 13.2 s
Wall time: 38 s