Ich muss programmgesteuert 10 Millionen Datensätze in eine Postgres-Datenbank einfügen. Gegenwärtig führe ich Tausende von Einfügeanweisungen in einer einzigen "Abfrage" aus.
Gibt es einen besseren Weg, dies zu tun, eine Bulk-Insert-Anweisung, von der ich nichts weiß?
postgresql
bulkinsert
Asche
quelle
quelle
Es gibt eine Alternative zur Verwendung von COPY, der von Postgres unterstützten Syntax für Mehrzeilenwerte. Aus der Dokumentation :
Der obige Code fügt zwei Zeilen ein, aber Sie können ihn beliebig erweitern, bis Sie die maximale Anzahl vorbereiteter Anweisungstoken erreicht haben (es könnte 999 US-Dollar sein, aber da bin ich mir nicht 100% sicher). Manchmal kann man COPY nicht verwenden, und dies ist ein würdiger Ersatz für diese Situationen.
quelle
Eine Möglichkeit, die Dinge zu beschleunigen, besteht darin, explizit mehrere Einfügungen oder Kopien innerhalb einer Transaktion durchzuführen (z. B. 1000). Das Standardverhalten von Postgres besteht darin, nach jeder Anweisung ein Commit durchzuführen. Wenn Sie also die Commits stapeln, können Sie einen gewissen Overhead vermeiden. Wie der Leitfaden in Daniels Antwort sagt, müssen Sie möglicherweise die automatische Festschreibung deaktivieren, damit dies funktioniert. Beachten Sie auch den Kommentar unten, der darauf hinweist, dass die Größe der wal_buffers auf 16 MB erhöht werden kann.
quelle
UNNEST
Funktion mit Arrays kann zusammen mit der Multirow-VALUES-Syntax verwendet werden. Ich denke , ich , dass diese Methode ist langsamer als die Verwendung ,COPY
aber es ist nützlich für mich in der Arbeit mit psycopg und Python (Pythonlist
weitergegebencursor.execute
wird pgARRAY
):ohne
VALUES
Unterauswahl mit zusätzlicher Existenzprüfung:die gleiche Syntax für Massenaktualisierungen:
quelle
Sie können verwenden,
COPY table TO ... WITH BINARY
was " etwas schneller als die Text- und CSV-Formate " ist. Tun Sie dies nur, wenn Sie Millionen von Zeilen einfügen müssen und wenn Sie mit Binärdaten vertraut sind.Hier ist ein Beispielrezept in Python, das psycopg2 mit binärer Eingabe verwendet .
quelle
Dies hängt hauptsächlich von der (anderen) Aktivität in der Datenbank ab. Mit solchen Vorgängen wird die gesamte Datenbank für andere Sitzungen effektiv eingefroren. Eine weitere Überlegung ist das Datenmodell und das Vorhandensein von Einschränkungen, Auslösern usw.
Mein erster Ansatz ist immer: Erstellen Sie eine (temporäre) Tabelle mit einer Struktur ähnlich der Zieltabelle (erstellen Sie eine Tabelle tmp AS select * from target mit 1 = 0) und lesen Sie zunächst die Datei in die temporäre Tabelle. Dann überprüfe ich, was überprüft werden kann: Duplikate, Schlüssel, die bereits im Ziel vorhanden sind usw.
Dann mache ich einfach ein "In Ziel einfügen select * from tmp" oder ähnliches.
Wenn dies fehlschlägt oder zu lange dauert, brich ich es ab und erwäge andere Methoden (vorübergehendes Löschen von Indizes / Einschränkungen usw.)
quelle
Ich habe einen sehr schnellen Postgresq Data Loader mit nativen libpq-Methoden implementiert. Probieren Sie mein Paket https://www.nuget.org/packages/NpgsqlBulkCopy/ aus.
quelle
Ich bin gerade auf dieses Problem gestoßen und würde csvsql ( Releases ) für Massenimporte nach Postgres empfehlen . Um eine Masseneinfügung durchzuführen, verwenden Sie einfach
createdb
und dann einecsvsql
, die eine Verbindung zu Ihrer Datenbank herstellt und einzelne Tabellen für einen gesamten Ordner mit CSVs erstellt.quelle
Die externe Datei ist die besten und typischsten Massendaten
Der Begriff "Massendaten" bezieht sich auf "viele Daten". Daher ist es selbstverständlich, Original-Rohdaten zu verwenden , ohne diese in SQL umwandeln zu müssen. Typische Rohdatendateien für "Masseneinfügungen" sind CSV- und JSON- Formate.
Masseneinsatz mit etwas Transformation
In ETL- Anwendungen und Aufnahmeprozessen müssen wir die Daten vor dem Einfügen ändern. Temporäre Tabellen belegen (viel) Speicherplatz, und dies ist nicht der schnellere Weg. Der PostgreSQL Foreign Wrapper (FDW) ist die beste Wahl.
CSV-Beispiel . Angenommen, die
tablename (x, y, z)
On-SQL- und eine CSV-Datei mögenSie können das klassische SQL
COPY
zum Laden ( wie auch für Originaldaten) verwendentmp_tablename
und gefilterte Daten intablename
... einfügen. Um jedoch den Festplattenverbrauch zu vermeiden, sollten Sie am besten direkt von aufnehmenSie müssen die Datenbank für FDW vorbereiten, und stattdessen
tmp_tablename_fdw
können Sie statisch eine Funktion verwenden, die sie generiert :JSON-Beispiel . Ein Satz von zwei Dateien,
myRawData1.json
undRanger_Policies2.json
kann durch eingenommen werden:Dabei liest die Funktion jsonb_read_files () alle Dateien eines Ordners, die durch eine Maske definiert sind:
Fehlendes gzip-Streaming
Die häufigste Methode zur "Dateiaufnahme" (hauptsächlich in Big Data) besteht darin, die Originaldatei im gzip-Format beizubehalten und mit zu übertragen Streaming-Algorithmus zu alles, was in Unix-Pipes schnell und ohne Disc-Verbrauch ausgeführt werden kann:
Ideal (Zukunft) ist also eine Serveroption für das Format
.csv.gz
.quelle