Saltar al contenido

Cómo acelerar la inserción masiva en MS SQL Server desde CSV usando pyodbc

Solución:

Como se señaló en un comentario a otra respuesta, el T-SQL BULK INSERT El comando solo funcionará si el archivo que se va a importar está en la misma máquina que la instancia de SQL Server o si está en una ubicación de red SMB / CIFS que la instancia de SQL Server pueda leer. Por lo tanto, es posible que no sea aplicable en el caso de que el archivo de origen esté en un cliente remoto.

pyodbc 4.0.19 agregó una función Cursor # fast_executemany que puede ser útil en ese caso. fast_executemany está “desactivado” de forma predeterminada, y el siguiente código de prueba …

cnxn = pyodbc.connect(conn_str, autocommit=True)
crsr = cnxn.cursor()
crsr.execute("TRUNCATE TABLE fast_executemany_test")

sql = "INSERT INTO fast_executemany_test (txtcol) VALUES (?)"
params = [(f'txt{i:06d}',) for i in range(1000)]
t0 = time.time()
crsr.executemany(sql, params)
print(f'{time.time() - t0:.1f} seconds')

… tomó aproximadamente 22 segundos para ejecutarse en mi máquina de prueba. Simplemente agregando crsr.fast_executemany = True

cnxn = pyodbc.connect(conn_str, autocommit=True)
crsr = cnxn.cursor()
crsr.execute("TRUNCATE TABLE fast_executemany_test")

crsr.fast_executemany = True  # new in pyodbc 4.0.19

sql = "INSERT INTO fast_executemany_test (txtcol) VALUES (?)"
params = [(f'txt{i:06d}',) for i in range(1000)]
t0 = time.time()
crsr.executemany(sql, params)
print(f'{time.time() - t0:.1f} seconds')

… redujo el tiempo de ejecución a poco más de 1 segundo.

Actualización: como se señaló en el comentario de @SimonLang, BULK INSERT en SQL Server 2017 y versiones posteriores aparentemente admite calificadores de texto en archivos CSV (ref: aquí).


Es casi seguro que BULK INSERT será mucho más rápido que leer el archivo fuente fila por fila y hacer un INSERT regular para cada fila. Sin embargo, tanto BULK INSERT como BCP tienen una limitación significativa con respecto a los archivos CSV, ya que no pueden manejar calificadores de texto (ref: aquí). Es decir, si su archivo CSV no no tienen cadenas de texto calificadas en él …

1,Gord Thompson,2015-04-15
2,Bob Loblaw,2015-04-07

… entonces puede INSERTARLO EN GRUPO, pero si contiene calificadores de texto (porque algunos valores de texto contienen comas) …

1,"Thompson, Gord",2015-04-15
2,"Loblaw, Bob",2015-04-07

… entonces BULK INSERT no puede manejarlo. Aún así, podría ser más rápido en general preprocesar un archivo CSV de este tipo en un archivo delimitado por tuberías …

1|Thompson, Gord|2015-04-15
2|Loblaw, Bob|2015-04-07

… o un archivo delimitado por tabulaciones (donde representa el carácter de tabulación) …

1→Thompson, Gord→2015-04-15
2→Loblaw, Bob→2015-04-07

… y luego INSERTAR BULK ese archivo. Para el último archivo (delimitado por tabulaciones), el código BULK INSERT se vería así:

import pypyodbc
conn_str = "DSN=myDb_SQLEXPRESS;"
cnxn = pypyodbc.connect(conn_str)
crsr = cnxn.cursor()
sql = """
BULK INSERT myDb.dbo.SpikeData123
FROM 'C:\__tmp\biTest.txt' WITH (
    FIELDTERMINATOR='\t',
    ROWTERMINATOR='\n'
    );
"""
crsr.execute(sql)
cnxn.commit()
crsr.close()
cnxn.close()

Nota: Como se menciona en un comentario, la ejecución de un BULK INSERT La declaración solo es aplicable si la instancia de SQL Server puede leer directamente el archivo de origen. Para los casos en los que el archivo de origen está en un cliente remoto, consulte esta respuesta.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *