Попытка вставить + 2M строк в MSSQL с использованием pyodbc заняла абсурдно много времени по сравнению с массовыми операциями в Postgres (psycopg2) и Oracle (cx_Oracle). У меня не было привилегий для использования операции BULK INSERT, но я смог решить проблему с помощью метода ниже.
Многие решения правильно предлагают fast_executemany, однако есть некоторые хитрости для его правильного использования. Во-первых, я заметил, что pyodbc выполнял коммит после каждой строки, когда для autocommit было установлено значение True в методе connect, поэтому для него должно быть установлено значение False. Я также наблюдал нелинейное замедление при вставке более чем ~ 20 тыс. Строк за раз, то есть вставка 10 тыс. Строк была подсекундной, но 50 тыс. Выше 20 с. Я предполагаю, что журнал транзакций становится довольно большим и замедляет все это. Поэтому вы должны разделить свою вставку и зафиксировать после каждого фрагмента. Я обнаружил, что 5 тыс. Строк на чанк обеспечивают хорошую производительность, но это, очевидно, будет зависеть от многих факторов (данных, машины, конфигурации БД и т. Д.).
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()