Ich muss mehrere Zeilen mit einer Abfrage einfügen (die Anzahl der Zeilen ist nicht konstant), daher muss ich eine Abfrage wie diese ausführen:
INSERT INTO t (a, b) VALUES (1, 2), (3, 4), (5, 6);
Der einzige Weg, den ich kenne, ist
args = [(1,2), (3,4), (5,6)]
args_str = ','.join(cursor.mogrify("%s", (x, )) for x in args)
cursor.execute("INSERT INTO t (a, b) VALUES "+args_str)
aber ich möchte einen einfacheren Weg.
python
postgresql
psycopg2
Sergey Fedoseev
quelle
quelle
execute
Strategie zu verwenden. Dank dessen habe ich eine Beschleunigung von ungefähr 100x gesehen!executemany
nach jeder Einfügung ein Commit ausgeführt. Wenn Sie stattdessen das Ganze in eine Transaktion einwickeln, würde dies möglicherweise die Dinge beschleunigen?executemany
macht psycopg2's nichts Optimales, nur Schleifen und macht vieleexecute
Aussagen. Mit dieser Methode wurde eine Einfügung von 700 Zeilen auf einen Remote-Server von 60 Sekunden auf <2 Sekunden verschoben.+
scheint sich für eine SQL-Injektion zu öffnen. Ich denke, die @ Clodoaldo Neto-execute_values()
Lösung ist sicherer.Neue
execute_values
Methode in Psycopg 2.7:Die pythonische Methode in Psycopg 2.6:
Erläuterung: Wenn die einzufügenden Daten als Liste von Tupeln wie in angegeben sind
dann ist es schon im genau gewünschten format als
Die
values
Syntax derinsert
Klausel erwartet eine Liste von Datensätzen wie ininsert into t (a, b) values (1, 'x'),(2, 'y')
Psycopg
passt einen Pythontuple
an einen Postgresql anrecord
.Die einzige notwendige Arbeit besteht darin, eine Datensatzlistenvorlage bereitzustellen, die von psycopg ausgefüllt werden soll
und platzieren Sie es in der
insert
AbfrageDrucken der
insert_query
AusgängeNun zu den üblichen
Psycopg
ArgumentationsersetzungenOder testen Sie einfach, was an den Server gesendet wird
Ausgabe:
quelle
execute_values
konnte ich mein System mit 1k Datensätzen pro Minute bis zu 128k Datensätzen pro Minute zumUpdate mit psycopg2 2.7:
Der Klassiker
executemany()
ist ungefähr 60-mal langsamer als die Implementierung von @ ant32 ("gefaltet" genannt), wie in diesem Thread erläutert: https://www.postgresql.org/message-id/20170130215151.GA7081%40deb76.aryehleib.comDiese Implementierung wurde in Version 2.7 zu psycopg2 hinzugefügt und heißt
execute_values()
:Vorherige Antwort:
Das Einfügen mehrerer Zeilen ist mit der Multirow-
VALUES
Syntax mitexecute()
etwa 10-mal schneller als mit psycopg2executemany()
. Tatsächlich,executemany()
läuft nur viele einzelneINSERT
Aussagen.Der Code von @ ant32 funktioniert perfekt in Python 2. In Python 3 werden jedoch
cursor.mogrify()
Bytes zurückgegeben,cursor.execute()
entweder Bytes oder Zeichenfolgen verwendet, und','.join()
str
Instanz erwartet .In Python 3 müssen Sie möglicherweise den Code von @ ant32 ändern, indem Sie Folgendes hinzufügen
.decode('utf-8')
:Oder indem Sie nur Bytes (mit
b''
oderb""
) verwenden:quelle
cursor.copy_from ist die mit Abstand schnellste Lösung, die ich für Masseneinsätze gefunden habe. Hier ist eine Zusammenfassung, die ich mit einer Klasse namens IteratorFile erstellt habe, mit der ein Iterator, der Zeichenfolgen liefert, wie eine Datei gelesen werden kann. Wir können jeden Eingabedatensatz mithilfe eines Generatorausdrucks in eine Zeichenfolge konvertieren. Die Lösung wäre also
Für diese triviale Größe von Argumenten macht es keinen großen Geschwindigkeitsunterschied, aber ich sehe große Beschleunigungen, wenn es um Tausende von Zeilen geht. Es ist außerdem speichereffizienter als das Erstellen einer riesigen Abfragezeichenfolge. Ein Iterator würde immer nur einen Eingabedatensatz gleichzeitig im Speicher halten, wobei Ihnen irgendwann der Speicher in Ihrem Python-Prozess oder in Postgres ausgeht, indem Sie die Abfragezeichenfolge erstellen.
quelle
Ein Ausschnitt aus der Tutorial-Seite von Psycopg2 auf Postgresql.org (siehe unten) :
Es speichert nicht viel Code, sieht aber definitiv besser aus.
quelle
INSERT
Anweisungen ausgeführt. Nützlich, aber nicht dasselbe wie ein einzelner MehrfacheinsatzVALUE
.Alle diese Techniken werden in der Postgres-Terminologie als "Extended Inserts" bezeichnet. Ab dem 24. November 2016 ist sie immer noch eine Tonne schneller als die Executemany () von psychopg2 () und alle anderen in diesem Thread aufgeführten Methoden (die ich ausprobiert habe, bevor ich dazu gekommen bin) Antworten).
Hier ist ein Code, der cur.mogrify nicht verwendet und nett und einfach ist, um sich zurechtzufinden:
Es sollte jedoch beachtet werden, dass Sie copy_from () verwenden sollten, wenn Sie copy_from () verwenden können;)
quelle
Ich benutze die obige Antwort von ant32 seit mehreren Jahren. Ich habe jedoch festgestellt, dass dies ein Fehler in Python 3 ist, da
mogrify
eine Byte-Zeichenfolge zurückgegeben wird.Das explizite Konvertieren in Bytse-Zeichenfolgen ist eine einfache Lösung, um Code Python 3 kompatibel zu machen.
quelle
Ein weiterer netter und effizienter Ansatz besteht darin, Zeilen zum Einfügen als 1 Argument zu übergeben, bei dem es sich um ein Array von JSON-Objekten handelt.
ZB Sie übergeben Argument:
Es ist ein Array, das eine beliebige Anzahl von Objekten enthalten kann. Dann sieht Ihr SQL so aus:
Hinweis: Ihr Postgress muss neu genug sein, um json zu unterstützen
quelle
Die Lösung cursor.copyfrom , bereitgestellt von @ jopseph.sheedy ( https://stackoverflow.com/users/958118/joseph-sheedy ) oben ( https://stackoverflow.com/a/30721460/11100064) ) ist in der Tat blitzschnell.
Das Beispiel, das er gibt, ist jedoch nicht generisch für einen Datensatz mit einer beliebigen Anzahl von Feldern verwendbar, und ich habe einige Zeit gebraucht, um herauszufinden, wie man es richtig verwendet.
Die Iterator-Datei muss mit solchen durch Tabulatoren getrennten Feldern instanziiert werden (
r
ist eine Liste von Diktaten, in denen jedes Diktat ein Datensatz ist):Um eine beliebige Anzahl von Feldern zu verallgemeinern, erstellen wir zuerst eine Zeilenzeichenfolge mit der richtigen Anzahl von Registerkarten und Feldplatzhaltern:
"{}\t{}\t{}....\t{}"
und geben dann.format()
die Feldwerte ein*list(r.values())) for r in records
::vollständige Funktion im Kern hier .
quelle
Wenn Sie SQLAlchemy verwenden, müssen Sie sich nicht mit der Handarbeit der Zeichenfolge herumschlagen, da SQLAlchemy das Generieren einer mehrzeiligen
VALUES
Klausel für eine einzelneINSERT
Anweisung unterstützt :quelle
insert_query
Zeile auf. Dannsession.execute()
wird nur die Anweisung von psycopg2execute()
mit einer einzigen massiven Zeichenfolge aufgerufen . Der "Trick" besteht also darin, zuerst das gesamte Objekt der Einfügeanweisung zu erstellen. Ich verwende dies, um 200.000 Zeilen gleichzeitig einzufügen, und habe mit diesem Code massive Leistungssteigerungen im Vergleich zum Normalcode festgestelltexecutemany()
.execute_batch wurde zu psycopg2 hinzugefügt, seit diese Frage gestellt wurde.
Es ist langsamer als execute_values, aber einfacher zu verwenden.
quelle
execute_values
ist schneller alsexecute_batch
Executemany akzeptieren Array von Tupeln
https://www.postgresqltutorial.com/postgresql-python/insert/
quelle
Wenn Sie mehrere Zeilen in eine Einfügestatistik einfügen möchten (vorausgesetzt, Sie verwenden kein ORM), ist es für mich bisher am einfachsten, eine Liste von Wörterbüchern zu verwenden. Hier ist ein Beispiel:
Wie Sie sehen, wird nur eine Abfrage ausgeführt:
quelle
Verwenden von Aiopg - Das folgende Snippet funktioniert einwandfrei
quelle
Schließlich wird in der SQLalchemy1.2-Version diese neue Implementierung hinzugefügt, um psycopg2.extras.execute_batch () anstelle von executemany zu verwenden, wenn Sie Ihre Engine mit use_batch_mode = True initialisieren, wie:
http://docs.sqlalchemy.org/en/latest/changelog/migration_12.html#change-4109
Dann müsste jemand SQLalchmey verwenden, um verschiedene Kombinationen von sqla und psycopg2 auszuprobieren und SQL gemeinsam zu steuern.
quelle