Pandas: to_sql ist zu langsam

Erstellt am 1. Feb. 2017  ·  24Kommentare  ·  Quelle: pandas-dev/pandas

Codebeispiel,

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

Problembeschreibung

Ich schreibe einen Datenrahmen mit 500.000 Zeilen in eine Postgres-AWS-Datenbank und es dauert sehr, sehr lange, die Daten durchzuschieben.

Es ist ein ziemlich großer SQL-Server und meine Internetverbindung ist ausgezeichnet, daher habe ich ausgeschlossen, dass diese zum Problem beitragen.

Im Vergleich dazu ist csv2sql oder die Verwendung von cat und Piping in psql in der Befehlszeile viel schneller.

IO SQL Usage Question

Hilfreichster Kommentar

Fügen Sie diesen Code unter 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()

In meinem Code dauerte die Ausführung der to_sql -Funktion 7 Minuten, und jetzt dauert es nur noch 5 Sekunden;)

Alle 24 Kommentare

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

Mit SQLServer müssen Sie aus Effizienzgründen über CSV mit einem Massen-Upload importieren

Dies könnte hilfreich sein: http://odo.pydata.org/en/latest/perf.html

ODO würde bei mir nicht funktionieren, es erzeugt Fehler, die ich nicht beheben konnte, aber d6tstack hat einwandfrei funktioniert https://github.com/d6t/d6tstack/blob/master/examples-sql.ipynb. Sie können mit Pandas vorverarbeiten und es wird postgres COPY FROM verwendet, um den Import schnell zu machen. Funktioniert gut mit RDS-Postgres.

Fügen Sie diesen Code unter 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()

In meinem Code dauerte die Ausführung der to_sql -Funktion 7 Minuten, und jetzt dauert es nur noch 5 Sekunden;)

Danke @llautert!
Das hat sehr geholfen!

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

Ich habe versucht, dieses Update auszuführen, habe jedoch eine Fehlermeldung erhalten:

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

Weiß jemand was los ist?

Hey @ tim-sauchuk, der ebenfalls auf denselben Fehler stößt, obwohl ich eine Lösung gefunden habe, die hervorragend funktioniert und eine leichte Bearbeitung der Datei pandas.io.sql.py beinhaltet (löschen Sie einfach die .pyc-Datei aus __pycache__, bevor Sie sie erneut importieren um sicherzustellen, dass die neue Version in die komprimierte Datei geschrieben wird)

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

Hey @ tim-sauchuk, der ebenfalls auf den gleichen Fehler stößt, obwohl ich eine Lösung gefunden habe, die hervorragend funktioniert und eine leichte Bearbeitung der Datei pandas.io.sql.py beinhaltet (löschen Sie einfach die .pyc-Datei aus pycache, bevor Sie sie erneut importieren um sicherzustellen, dass die neue Version in die komprimierte Datei geschrieben wird)

8953

Das von @ bsaunders23 erwähnte Problem Nr. 8953 zeigt auch einen Weg zum "Affen-Patch" (zur Laufzeit beheben). Ich habe es versucht, und ein 20k-Datensatz, dessen Hochladen mehr als 10 Minuten dauerte, dauerte nur 4 Sekunden.

Danke @llautert!
Das hat sehr geholfen!

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

Weiß jemand, wie ich diese Lösung in einer Klasse mit einer self.engine-Instanz implementieren kann?

Weiß jemand, wie ich diese Lösung in einer Klasse mit einer self.engine-Instanz implementieren kann?

Funktioniert für mich unter Bezugnahme auf self.engine

Beispiel:

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

Funktioniert bei mir nicht Welche Pandas und SQLalchemy-Version verwenden Sie?

Ich habe versucht, sqlalchemy auszuführen: 1.2.4-py35h14c3975_0 und 1.2.11-py35h7b6447c_0

aber ich bekomme

AttributeError: Das Objekt 'psycopg2.extensions.cursor' hat kein Attribut 'fast_executemany'.

@ dean12 @llautert

Wie sieht der Funktionsaufruf in diesem Zusammenhang aus? Oder mit anderen Worten, was verwenden Sie für die Argumente, um die Tabelle erfolgreich hochzuladen?

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

Ich habe versucht, sqlalchemy auszuführen: 1.2.4-py35h14c3975_0 und 1.2.11-py35h7b6447c_0

aber ich bekomme

AttributeError: Das Objekt 'psycopg2.extensions.cursor' hat kein Attribut 'fast_executemany'.

Sie verwenden psycopg2, einen Postgresql-Treiber. Dieses Problem und dieser Fix betreffen Microsoft SQL Server mit dem pyodbc-Treiber.

Was ist mit dem Parameter 'dtype'?

Weiß jemand, wie ich diese Lösung in einer Klasse mit einer self.engine-Instanz implementieren kann?

Funktioniert für mich unter Bezugnahme auf self.engine

Beispiel:

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

Hast du herausgefunden wie?

Ich denke, die richtige Antwort sollte sein, https://docs.sqlalchemy.org/en/13/dialects/postgresql.html#psycopg2 -batch-mode-fast-execute zu verwenden, wenn Sie versuchen, pandas dataframe zu sparen postgres

Eine neue Version von Pandas enthält den Parameter method , der als "Multi" ausgewählt werden kann. Dadurch wird der Code viel schneller ausgeführt.

fast_executemany kann jetzt in einem einzigen Schritt ausgeführt werden (sqlalchemy> = 1.3.0):

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

Vielleicht lohnt es sich, es irgendwo in den Dokumenten oder mit einem Beispiel zu erwähnen? Es ist ein besonderer Fall, der nicht mit Pandas zusammenhängt, aber es ist eine kleine Ergänzung, die in vielen Fällen die Leistung drastisch verbessern könnte.

Eine neue Version von Pandas enthält den Parameter method , der als "Multi" ausgewählt werden kann. Dadurch wird der Code viel schneller ausgeführt.

Sie würden denken, dass das Setzen des Parameters chunksize ausreichen würde, um to_sql Batch einzufügen, aber nein.

Eine Alternative für MS SQL-Benutzer ist die Verwendung von turbodbc.Cursor.insertmanycolumns . Dies habe ich im verknüpften StackOverflow-Beitrag erklärt: https://stackoverflow.com/a/62671681/1689261

Für zukünftige Leser gibt es zwei Möglichkeiten, einen 'batch_mode' für to_sql zu verwenden. Das Folgende sind die zwei Kombinationen:

create_engine(connection_string, executemany_mode='batch', executemany_batch_page_size=x)

oder

create_engine(connection_string, executemany_mode='values', executemany_values_page_size=x)

Details zu diesen Argumenten finden Sie hier: https://docs.sqlalchemy.org/en/13/dialects/postgresql.html#psycopg2 -fast-execute-helpers

Für Postgres-Benutzer empfehle ich, method auf einen aufrufbaren

Aufrufbar mit Signatur (pd_table, conn, keys, data_iter): Dies kann verwendet werden, um eine leistungsfähigere Einfügemethode zu implementieren, die auf bestimmten Backend-Dialektfunktionen basiert.

und rufen Sie die Funktion aus dem Beispielcode hier auf: https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html#insertion -method and

Die Verwendung von COPY FROM ist wirklich viel schneller 🚀

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen