Python pyodbc启用fast_executemany后executemany无法执行求助
pyodbc fast_executemany 导致 executemany 无响应问题排查
问题场景
你编写的批量插入代码在开启fast_executemany后,执行到executed 3就卡住,无法完成executemany及后续步骤;注释掉mycursor.fast_executemany = True后代码可正常运行,但10000条数据耗时约45秒。
你的代码如下:
def fast_execute(): mydb = pyodbc.connect(connection_string,autocommit=True) mycursor = mydb.cursor() mycursor.execute("use care_new") mycursor.execute("truncate dummytable") print('executed 1') mycursor.fast_executemany = True print('executed 2') query = "insert into dummytable(ID, Name) values(?,?)" value = [((f'{i}'),(f'Names{str(i)}'),) for i in range(10000)] t0 = time.time() print('executed 3') mycursor.executemany(query, value) print('executed 4') print(f'{time.time() - t0:.1f} seconds for fast execute many') mydb.close()
执行输出:
executed 1 executed 2 executed 3
可能的原因及解决办法
1. 数据类型不匹配(最常见)
fast_executemany对数据类型的兼容性远不如普通executemany,它不会自动转换数据类型。如果你的dummytable中ID字段是整数类型,但你生成的value里ID是字符串(f'{i}'),就会导致批量插入卡住。
解决:把ID改为整数类型,和表字段匹配:
value = [(i, f'Names{i}') for i in range(10000)]
2. autocommit与fast_executemany兼容性问题
部分场景下,连接时设置autocommit=True会和fast_executemany的批量提交逻辑冲突,导致阻塞。
解决:去掉连接时的autocommit=True,在executemany后手动提交:
mydb = pyodbc.connect(connection_string) # 移除autocommit=True # ... 其他代码 ... mycursor.executemany(query, value) mydb.commit() # 手动提交
3. ODBC驱动版本过旧
旧版本的ODBC驱动对fast_executemany的支持不完善,比如SQL Server的ODBC Driver 13及以下版本容易出现这类问题。
解决:升级到最新版的ODBC驱动(比如ODBC Driver 17/18 for SQL Server)。
4. 表约束/触发器阻塞
如果dummytable有主键约束、唯一约束或者触发器,fast_executemany批量插入时的约束检查、触发器触发逻辑和普通executemany不同,可能导致锁表或阻塞。
解决:临时禁用约束/触发器测试,或者检查数据库是否有锁表情况,调整约束或触发器逻辑。
修正后的示例代码
def fast_execute(): import pyodbc import time mydb = pyodbc.connect(connection_string) mycursor = mydb.cursor() mycursor.execute("use care_new") mycursor.execute("truncate dummytable") print('executed 1') mycursor.fast_executemany = True print('executed 2') query = "insert into dummytable(ID, Name) values(?,?)" # 匹配字段数据类型 value = [(i, f'Names{i}') for i in range(10000)] t0 = time.time() print('executed 3') mycursor.executemany(query, value) mydb.commit() print('executed 4') print(f'{time.time() - t0:.1f} seconds for fast execute many') mydb.close()
内容的提问来源于stack exchange,提问作者Abhinav
相关产品推荐
相关产品推荐

