say*_*yap 21 sql-server bulkinsert pyodbc
有了这个表:
CREATE TABLE test_insert (
col1 INT,
col2 VARCHAR(10),
col3 DATE
)
Run Code Online (Sandbox Code Playgroud)
以下代码需要40秒才能运行:
import pyodbc
from datetime import date
conn = pyodbc.connect('DRIVER={SQL Server Native Client 10.0};'
'SERVER=localhost;DATABASE=test;UID=xxx;PWD=yyy')
rows = []
row = [1, 'abc', date.today()]
for i in range(10000):
rows.append(row)
cursor = conn.cursor()
cursor.executemany('INSERT INTO test_insert VALUES (?, ?, ?)', rows)
conn.commit()
Run Code Online (Sandbox Code Playgroud)
psycopg2的等效代码只需3秒.我不认为mssql比postgresql慢得多.有关如何在使用pyodbc时提高批量插入速度的任何想法?
编辑:在ghoerz发现之后添加一些注释
在pyodbc中,流程executemany
是:
在ceODBC,流程executemany
是:
小智 11
我使用executemany()将pyODBC插入SQL Server 2008数据库时遇到了类似的问题.当我在SQL端运行探查器跟踪时,pyODBC正在创建连接,准备参数化的insert语句,并为一行执行它.然后它会对语句毫无准备,并关闭连接.然后它为每一行重复此过程.
我没能在pyODBC中找到任何没有这样做的解决方案.我最终切换到ceODBC连接到SQL Server,它正确地使用了参数化语句.
小智 5
与 Postgres (psycopg2) 和 Oracle (cx_Oracle) 中的批量操作相比,尝试使用 pyodbc 将 +2M 行插入 MSSQL 花费了荒谬的长时间。我没有使用 BULK INSERT 操作的权限,但能够通过以下方法解决问题。
许多解决方案正确地建议了 fast_executemany,但是,有一些技巧可以正确使用它。首先,我注意到当自动提交在连接方法中设置为 True 时,pyodbc 在每一行之后提交,因此必须将其设置为 False。当一次插入超过 20k 行时,我还观察到非线性减速,即插入 10k 行是亚秒,但 50k 是 20 秒以上。我假设事务日志变得非常大并且减慢了整个过程。因此,您必须在每个块之后分块插入和提交。我发现每块 5k 行提供了良好的性能,但这显然取决于许多因素(数据、机器、数据库配置等...)。
import pyodbc
CHUNK_SIZE = 5000
def chunks(l, n):
"""Yield successive n-sized chunks from l."""
for i in xrange(0, len(l), n): #use xrange in python2, range in python3
yield l[i:i + n]
mssql_conn = pyodbc.connect(driver='{ODBC Driver 17 for SQL Server}',
server='<SERVER,PORT>',
timeout=1,
port=<PORT>,
uid=<UNAME>,
pwd=<PWD>,
TDS_Version=7.2,
autocommit=False) #IMPORTANT
mssql_cur = mssql_conn.cursor()
mssql_cur.fast_executemany = True #IMPORTANT
params = [tuple(x) for x in df.values]
stmt = "truncate table <THE TABLE>"
mssql_cur.execute(stmt)
mssql_conn.commit()
stmt = """
INSERT INTO <THE TABLE> (field1...fieldn) VALUES (?,...,?)
"""
for chunk in chunks(params, CHUNK_SIZE): #IMPORTANT
mssql_cur.executemany(stmt, chunk)
mssql_conn.commit()
Run Code Online (Sandbox Code Playgroud)