Pandas: to_sql est trop lent

Créé le 1 févr. 2017  ·  24Commentaires  ·  Source: pandas-dev/pandas

Exemple de code,

df_name.to_sql('table_name',
                          schema = 'public',
                          con = engine,
                          index = False,
                          if_exists = 'replace')

Description du problème

J'écris une trame de données de 500000 lignes dans une base de données AWS postgres et il faut très, très longtemps pour transmettre les données.

C'est un serveur SQL assez volumineux et ma connexion Internet est excellente, j'ai donc exclu ceux-ci comme contribuant au problème.

En comparaison, csv2sql ou l'utilisation de cat et de piping dans psql sur la ligne de commande est beaucoup plus rapide.

IO SQL Usage Question

Commentaire le plus utile

Ajoutez ce code ci-dessous 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()

Dans mon code, l'exécution to_sql fonction

Tous les 24 commentaires

voir ici: http://stackoverflow.com/questions/33816918/write-large-pandas-dataframes-to-sql-server-database

avec SQLServer, vous devez importer via csv avec un téléchargement en masse pour plus d'efficacité

vous trouverez peut-être cela utile: http://odo.pydata.org/en/latest/perf.html

ODO ne fonctionnerait pas pour moi, cela génère des erreurs que je n'ai pas pu corriger, mais d6tstack a bien fonctionné https://github.com/d6t/d6tstack/blob/master/examples-sql.ipynb. Vous pouvez prétraiter avec pandas et il utilise postgres COPY FROM pour rendre l'importation rapide. Fonctionne bien avec les postgres RDS.

Ajoutez ce code ci-dessous 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()

Dans mon code, l'exécution to_sql fonction

Merci @llautert!
Cela a beaucoup aidé!

# 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()

J'ai essayé d'exécuter ce correctif, mais j'ai rencontré un message d'erreur:

AttributeError: 'psycopg2.extensions.cursor' object has no attribute 'fast_executemany'

Quelqu'un sait ce qui se passe?

Hey @ tim-sauchuk, rencontrant également la même erreur, bien que j'ai trouvé une solution qui fonctionne très bien, qui implique une légère modification du fichier pandas.io.sql.py (supprimez simplement le fichier .pyc de __pycache__ avant de réimporter pour s'assurer qu'il écrit la nouvelle version dans le fichier compressé)

https://github.com/pandas-dev/pandas/issues/8953

Hey @ tim-sauchuk, rencontrant également la même erreur, même si j'ai trouvé une solution qui fonctionne très bien, qui implique une légère modification du fichier pandas.io.sql.py (supprimez simplement le fichier .pyc de pycache avant de

8953

Le problème n ° 8953 mentionné par @ bsaunders23 montre également un moyen de "patch monkey" (corrigez-le au moment de l'exécution). Je l'ai essayé, et un ensemble de données de 20k qui a pris plus de 10 minutes à télécharger n'a pris que 4 secondes.

Merci @llautert!
Cela a beaucoup aidé!

# 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()

Quelqu'un sait-il comment je peux implémenter cette solution dans une classe avec une instance self.engine?

Quelqu'un sait-il comment je peux implémenter cette solution dans une classe avec une instance self.engine?

Fonctionne pour moi en se référant à self.engine

Exemple:

    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()

Ça ne marche pas pour moi. Quelle version de pandas et de sqlalchemy utilisez-vous?

Je l'ai essayé en exécutant sqlalchemy: 1.2.4-py35h14c3975_0 et 1.2.11-py35h7b6447c_0

mais je reçois

AttributeError: l'objet 'psycopg2.extensions.cursor' n'a pas d'attribut 'fast_executemany'

@ dean12 @llautert

À quoi ressemble l'appel de fonction dans ce contexte? Ou en d'autres termes, qu'utilisez-vous pour que les arguments réussissent à télécharger la table?

<# 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()>``

Je l'ai essayé en exécutant sqlalchemy: 1.2.4-py35h14c3975_0 et 1.2.11-py35h7b6447c_0

mais je reçois

AttributeError: l'objet 'psycopg2.extensions.cursor' n'a pas d'attribut 'fast_executemany'

Vous utilisez psycopg2, qui est un pilote postgresql. Ce problème et ce correctif concernent Microsoft SQL Server à l'aide du pilote pyodbc.

qu'en est-il d'ajouter le paramètre 'dtype'

Quelqu'un sait-il comment je peux implémenter cette solution dans une classe avec une instance self.engine?

Fonctionne pour moi en se référant à self.engine

Exemple:

    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()

Avez-vous découvert comment?

Je pense que la bonne réponse devrait être d'utiliser https://docs.sqlalchemy.org/en/13/dialects/postgresql.html#psycopg2 -batch-mode-fast-execution, si vous essayez d'économiser un pandas dataframe en postgres

Une nouvelle version de pandas contient le paramètre method qui pourrait être choisi comme «multi». Cela rend le code beaucoup plus rapide.

fast_executemany peut être effectué en une seule étape maintenant (sqlalchemy> = 1.3.0):

engine = sqlalchemy.create_engine(connection_string, fast_executemany=True)

Peut-être vaut-il la peine de le mentionner quelque part dans la documentation ou avec un exemple? C'est un cas particulier non lié aux pandas, mais c'est un petit ajout qui pourrait considérablement améliorer les performances dans de nombreux cas.

Une nouvelle version de pandas contient le paramètre method qui pourrait être choisi comme «multi». Cela rend le code beaucoup plus rapide.

Vous pourriez penser que définir le paramètre chunksize serait suffisant pour faire to_sql insertion par lots de

Une alternative pour les utilisateurs de MS SQL consiste également à utiliser turbodbc.Cursor.insertmanycolumns , je l'ai expliqué dans l'article lié StackOverflow: https://stackoverflow.com/a/62671681/1689261

Pour les futurs lecteurs à ce sujet, il existe deux options pour utiliser un 'batch_mode' pour to_sql. Voici les deux combinaisons:

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)

Des détails sur ces arguments peuvent être trouvés ici: https://docs.sqlalchemy.org/en/13/dialects/postgresql.html#psycopg2 -fast-execution-helpers

Pour les utilisateurs de postgres, je recommande de définir method sur un appelable:

appelable avec signature (pd_table, conn, keys, data_iter): Ceci peut être utilisé pour implémenter une méthode d'insertion plus performante basée sur des fonctionnalités de dialectes backend spécifiques.

et appelez la fonction à partir de l'exemple de code ici https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html#insertion -method et

Utiliser COPY FROM est vraiment beaucoup plus rapide 🚀

Cette page vous a été utile?
0 / 5 - 0 notes