df_name.to_sql('table_name',
schema = 'public',
con = engine,
index = False,
if_exists = 'replace')
Estou escrevendo um dataframe de 500.000 linhas para um banco de dados AWS do postgres e leva muito, muito tempo para enviar os dados.
É um servidor SQL bastante grande e minha conexão com a Internet é excelente, portanto, descartei aqueles que contribuem para o problema.
Em comparação, csv2sql ou usar cat e piping no psql na linha de comando é muito mais rápido.
veja aqui: http://stackoverflow.com/questions/33816918/write-large-pandas-dataframes-to-sql-server-database
com SQLServer você precisa importar via csv com um upload em massa para eficiência
você pode achar isso útil: http://odo.pydata.org/en/latest/perf.html
ODO não funcionaria para mim, ele gera erros que não fui capaz de corrigir, mas d6tstack funcionou bem https://github.com/d6t/d6tstack/blob/master/examples-sql.ipynb. Você pode pré-processar com o pandas e ele usa o postgres COPY FROM para tornar a importação rápida. Funciona bem com postgres RDS.
Adicione este código abaixo 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()
No meu código, a função to_sql
levava 7 minutos para ser executada e agora leva apenas 5 segundos;)
Obrigado @llautert!
Isso ajudou muito!
# 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()
Tentei executar essa correção, mas recebi uma mensagem de erro:
AttributeError: 'psycopg2.extensions.cursor' object has no attribute 'fast_executemany'
Alguém sabe o que está acontecendo?
Ei @ tim-sauchuk, encontrando o mesmo erro também, embora eu tenha encontrado uma solução que está funcionando muito bem que envolve uma pequena edição no arquivo pandas.io.sql.py (apenas exclua o arquivo .pyc de __pycache__ antes de importar novamente para certificar-se de que grava a nova versão no arquivo compactado)
Ei @ tim-sauchuk, encontrando o mesmo erro também, embora eu tenha encontrado uma solução que está funcionando muito bem que envolve uma pequena edição no arquivo pandas.io.sql.py (apenas exclua o arquivo .pyc do
8953
O problema # 8953 que @ bsaunders23 mencionou também mostra uma maneira de "corrigir o patch" (corrigi-lo em tempo de execução). Eu tentei, e um conjunto de dados de 20k que levou mais de 10 minutos para carregar, em seguida, levou apenas 4 segundos.
Obrigado @llautert!
Isso ajudou muito!# 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()
Alguém sabe como posso implementar essa solução dentro de uma classe com uma instância self.engine?
Alguém sabe como posso implementar essa solução dentro de uma classe com uma instância self.engine?
Funciona para mim referindo-se a self.engine
Exemplo:
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()
Nao funciona para mim. Qual versão de pandas e sqlalchemy você está usando?
Eu tentei executando sqlalchemy: 1.2.4-py35h14c3975_0 e 1.2.11-py35h7b6447c_0
mas estou conseguindo
AttributeError: o objeto 'psycopg2.extensions.cursor' não tem o atributo 'fast_executemany'
@ dean12 @llautert
Qual é a aparência da chamada de função neste contexto? Ou em outras palavras, o que você está usando como argumentos para fazer o upload da tabela com sucesso?
<# 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()>``
Eu tentei executando sqlalchemy: 1.2.4-py35h14c3975_0 e 1.2.11-py35h7b6447c_0
mas estou conseguindo
AttributeError: o objeto 'psycopg2.extensions.cursor' não tem o atributo 'fast_executemany'
Você está usando psycopg2, que é um driver postgresql. Esse problema e a correção pertencem ao Microsoft SQL Server usando o driver pyodbc.
que tal adicionar o parâmetro 'dtype'
Alguém sabe como posso implementar essa solução dentro de uma classe com uma instância self.engine?
Funciona para mim referindo-se a
self.engine
Exemplo:
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()
Você descobriu como?
Acho que a resposta correta deveria ser usar https://docs.sqlalchemy.org/en/13/dialects/postgresql.html#psycopg2 -batch-mode-fast-execution, se você estiver tentando salvar um pandas dataframe
para um postgres
Uma nova versão do pandas contém o parâmetro method
que pode ser escolhido como 'multi'. Isso faz com que o código seja executado muito mais rápido.
fast_executemany
pode ser executado em uma única etapa agora (sqlalchemy> = 1.3.0):
engine = sqlalchemy.create_engine(connection_string, fast_executemany=True)
Talvez valha a pena mencioná-lo em algum lugar nos documentos ou com um exemplo? É um caso particular não relacionado a pandas, mas é uma pequena adição que pode melhorar drasticamente o desempenho em muitos casos.
Uma nova versão do pandas contém o parâmetro
method
que pode ser escolhido como 'multi'. Isso faz com que o código seja executado muito mais rápido.
Você pensaria que definir o parâmetro chunksize
seria o suficiente para fazer to_sql
inserir em lote, mas não.
Uma alternativa para usuários do MS SQL é usar também turbodbc.Cursor.insertmanycolumns
, expliquei isso na postagem StackOverflow vinculada: https://stackoverflow.com/a/62671681/1689261
Para leitores futuros, há duas opções para usar um 'batch_mode' para to_sql. A seguir estão as duas combinações:
create_engine(connection_string, executemany_mode='batch', executemany_batch_page_size=x)
ou
create_engine(connection_string, executemany_mode='values', executemany_values_page_size=x)
Detalhes sobre esses argumentos podem ser encontrados aqui: https://docs.sqlalchemy.org/en/13/dialects/postgresql.html#psycopg2 -fast-execution-helpers
Para usuários de postgres, recomendo definir method
como um callable:
chamável com assinatura (pd_table, conn, keys, data_iter): Isso pode ser usado para implementar um método de inserção de melhor desempenho com base em recursos de dialeto de backend específicos.
e chame a função do código de exemplo aqui https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html#insertion -method e
Usar COPY FROM
é realmente muito mais rápido 🚀
Comentários muito úteis
Adicione este código abaixo de
engine = create_engine(connection_string)
:No meu código, a função
to_sql
levava 7 minutos para ser executada e agora leva apenas 5 segundos;)