df_name.to_sql('table_name',
schema = 'public',
con = engine,
index = False,
if_exists = 'replace')
Estoy escribiendo un marco de datos de 500.000 filas en una base de datos de AWS de postgres y lleva mucho, mucho tiempo enviar los datos.
Es un servidor SQL bastante grande y mi conexión a Internet es excelente, por lo que he descartado que contribuyan al problema.
En comparación, csv2sql o usar cat y canalizar a psql en la línea de comandos es mucho más rápido.
ver aquí: http://stackoverflow.com/questions/33816918/write-large-pandas-dataframes-to-sql-server-database
con SQLServer necesita importar a través de csv con una carga masiva para mayor eficiencia
le puede resultar útil: http://odo.pydata.org/en/latest/perf.html
ODO no funcionaría para mí, genera errores que no pude corregir, pero d6tstack funcionó bien https://github.com/d6t/d6tstack/blob/master/examples-sql.ipynb. Puede preprocesar con pandas y usa postgres COPY FROM para hacer la importación rápida. Funciona bien con RDS postgres.
Agregue este código debajo de engine = create_engine(connection_string)
:
from sqlalchemy import event
@event.listens_for(e, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
if executemany:
cursor.fast_executemany = True
cursor.commit()
En mi código, la función to_sql
tardaba 7 minutos en ejecutarse, y ahora solo tarda 5 segundos;)
¡Gracias @llautert!
¡Eso ayudó mucho!
# dont forget to import event
from sqlalchemy import event, create_engine
engine = create_engine(connection_string)
@event.listens_for(engine, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
if executemany:
cursor.fast_executemany = True
cursor.commit()
Intenté ejecutar esta solución, pero me encontré con un mensaje de error:
AttributeError: 'psycopg2.extensions.cursor' object has no attribute 'fast_executemany'
Alguien sabe que esta pasando?
Hola @ tim-sauchuk, también me encontré con el mismo error, aunque encontré una solución que ha funcionado muy bien, que implica una ligera edición en el archivo pandas.io.sql.py (simplemente elimine el archivo .pyc de __pycache__ antes de importar de nuevo para asegurarse de que escribe la nueva versión en el archivo comprimido)
Hola @ tim-sauchuk, también me encontré con el mismo error, aunque encontré una solución que ha funcionado muy bien que implica una ligera edición en el archivo pandas.io.sql.py (simplemente elimine el archivo .pyc de
8953
El problema # 8953 que @ bsaunders23 mencionó también muestra una forma de "parchear" (arreglarlo en tiempo de ejecución). Lo probé y un conjunto de datos de 20k que tardó más de 10 minutos en cargarse y luego solo tomó 4 segundos.
¡Gracias @llautert!
¡Eso ayudó mucho!# dont forget to import event from sqlalchemy import event, create_engine engine = create_engine(connection_string) @event.listens_for(engine, 'before_cursor_execute') def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany): if executemany: cursor.fast_executemany = True cursor.commit()
¿Alguien sabe cómo puedo implementar esta solución dentro de una clase con una instancia de self.engine?
¿Alguien sabe cómo puedo implementar esta solución dentro de una clase con una instancia de self.engine?
Funciona para mí refiriéndose a self.engine
Ejemplo:
self.engine = sqlalchemy.create_engine(connectionString, echo=echo)
self.connection = self.engine.connect()
@event.listens_for(self.engine, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
print("Listen before_cursor_execute - executemany: %s" % str(executemany))
if executemany:
cursor.fast_executemany = True
cursor.commit()
No me funciona. ¿Qué versión de pandas y sqlalchemy estás usando?
Lo probé ejecutando sqlalchemy: 1.2.4-py35h14c3975_0 y 1.2.11-py35h7b6447c_0
pero estoy consiguiendo
AttributeError: el objeto 'psycopg2.extensions.cursor' no tiene atributo 'fast_executemany'
@ dean12 @llautert
¿Cómo se ve la llamada a la función en este contexto? O en otras palabras, ¿qué está usando para que los argumentos carguen correctamente la tabla?
<# dont forget to import event
from sqlalchemy import event, create_engine
engine = create_engine(connection_string)
@event.listens_for(engine, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
if executemany:
cursor.fast_executemany = True
cursor.commit()>``
Lo probé ejecutando sqlalchemy: 1.2.4-py35h14c3975_0 y 1.2.11-py35h7b6447c_0
pero estoy consiguiendo
AttributeError: el objeto 'psycopg2.extensions.cursor' no tiene atributo 'fast_executemany'
Está utilizando psycopg2, que es un controlador de postgresql. Este problema y la solución pertenecen a Microsoft SQL Server mediante el controlador pyodbc.
¿qué pasa con agregar el parámetro 'dtype'
¿Alguien sabe cómo puedo implementar esta solución dentro de una clase con una instancia de self.engine?
Funciona para mí refiriéndose a
self.engine
Ejemplo:
self.engine = sqlalchemy.create_engine(connectionString, echo=echo) self.connection = self.engine.connect() @event.listens_for(self.engine, 'before_cursor_execute') def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany): print("Listen before_cursor_execute - executemany: %s" % str(executemany)) if executemany: cursor.fast_executemany = True cursor.commit()
¿Has averiguado cómo?
Creo que la respuesta correcta debería ser usar https://docs.sqlalchemy.org/en/13/dialects/postgresql.html#psycopg2 -batch-mode-fast-execution, si está tratando de ahorrar pandas dataframe
a postgres
Una nueva versión de pandas contiene el parámetro method
que podría elegirse para ser 'múltiple'. Esto hace que el código se ejecute mucho más rápido.
fast_executemany
se puede realizar en un solo paso ahora (sqlalchemy> = 1.3.0):
engine = sqlalchemy.create_engine(connection_string, fast_executemany=True)
¿Quizás vale la pena mencionarlo en algún lugar de los documentos o con un ejemplo? Es un caso particular no relacionado con los pandas, pero es una pequeña adición que podría mejorar drásticamente el rendimiento en muchos casos.
Una nueva versión de pandas contiene el parámetro
method
que podría elegirse para ser 'múltiple'. Esto hace que el código se ejecute mucho más rápido.
Pensaría que establecer el parámetro chunksize
sería suficiente para hacer una inserción por lotes de to_sql
pero no.
Una alternativa para los usuarios de MS SQL es usar también turbodbc.Cursor.insertmanycolumns
, lo he explicado en la publicación vinculada de StackOverflow: https://stackoverflow.com/a/62671681/1689261
Para los futuros lectores sobre esto, hay dos opciones para usar un 'batch_mode' para to_sql. Las siguientes son las dos combinaciones:
create_engine(connection_string, executemany_mode='batch', executemany_batch_page_size=x)
o
create_engine(connection_string, executemany_mode='values', executemany_values_page_size=x)
Los detalles sobre estos argumentos se pueden encontrar aquí: https://docs.sqlalchemy.org/en/13/dialects/postgresql.html#psycopg2 -fast-execution-helpers
Para los usuarios de postgres, recomiendo configurar method
en un invocable:
invocable con firma (pd_table, conn, keys, data_iter): esto se puede usar para implementar un método de inserción más eficaz basado en características específicas del dialecto de backend.
y llame a la función desde el código de ejemplo aquí https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html#insertion -method y
Usar COPY FROM
es mucho más rápido 🚀
Comentario más útil
Agregue este código debajo de
engine = create_engine(connection_string)
:En mi código, la función
to_sql
tardaba 7 minutos en ejecutarse, y ahora solo tarda 5 segundos;)