Ich teste die Postgres-Einfügungsleistung. Ich habe eine Tabelle mit einer Spalte mit der Nummer als Datentyp. Es gibt auch einen Index. Ich habe die Datenbank mit dieser Abfrage gefüllt:
insert into aNumber (id) values (564),(43536),(34560) ...
Mit der obigen Abfrage habe ich sehr schnell 4 Millionen Zeilen auf einmal 10.000 eingefügt. Nachdem die Datenbank 6 Millionen Zeilen erreicht hatte, ging die Leistung alle 15 Minuten drastisch auf 1 Million Zeilen zurück. Gibt es einen Trick, um die Einfügeleistung zu erhöhen? Ich benötige eine optimale Einfügeleistung für dieses Projekt.
Verwenden von Windows 7 Pro auf einem Computer mit 5 GB RAM.
sql
postgresql
bulkinsert
sql-insert
Luke101
quelle
quelle
Antworten:
Siehe Auffüllen einer Datenbank im PostgreSQL-Handbuch, Depesz 'ausgezeichneter Artikel zum Thema und diese SO-Frage .
(Beachten Sie, dass diese Antwort ist etwa Bulk-Laden von Daten in eine bestehende DB oder ein neues zu erstellen. Wenn Sie Interesse DB Leistung wiederherstellen mit
pg_restore
oderpsql
Ausführung vonpg_dump
Ausgabe, ein großer Teil davon gilt nicht dapg_dump
undpg_restore
schon Dinge tun , wie die Schaffung Trigger und Indizes nach Abschluss eines Schemas + Datenwiederherstellung) .Es gibt viel zu tun. Die ideale Lösung wäre, in eine
UNLOGGED
Tabelle ohne Indizes zu importieren , diese dann in protokolliert zu ändern und die Indizes hinzuzufügen. Leider wird in PostgreSQL 9.4 das Ändern von Tabellen vonUNLOGGED
in protokolliert nicht unterstützt . 9.5 fügt hinzuALTER TABLE ... SET LOGGED
, damit Sie dies tun können.Wenn Sie Ihre Datenbank für den Massenimport offline schalten können, verwenden Sie
pg_bulkload
.Andernfalls:
Deaktivieren Sie alle Trigger in der Tabelle
Löschen Sie die Indizes, bevor Sie mit dem Import beginnen, und erstellen Sie sie anschließend neu. (Das Erstellen eines Index in einem Durchgang dauert viel weniger lange als das schrittweise Hinzufügen derselben Daten, und der resultierende Index ist viel kompakter.)
Wenn Sie den Import innerhalb einer einzelnen Transaktion ausführen, können Sie sicher Fremdschlüsseleinschränkungen löschen, den Import durchführen und die Einschränkungen vor dem Festschreiben neu erstellen. Tun Sie dies nicht, wenn der Import auf mehrere Transaktionen aufgeteilt ist, da Sie möglicherweise ungültige Daten einführen.
Wenn möglich, verwenden Sie
COPY
anstelle vonINSERT
sWenn Sie nicht verwenden können, sollten Sie
COPY
mehrwertigeINSERT
s verwenden, wenn dies praktikabel ist. Sie scheinen dies bereits zu tun. Versuchen Sie jedoch nicht, zu viele Werte in einem einzigenVALUES
aufzulisten. Diese Werte müssen ein paar Mal in den Speicher passen. Halten Sie sie daher auf einige Hundert pro Anweisung.Batch Ihre Einfügungen in explizite Transaktionen, wobei Hunderttausende oder Millionen von Einfügungen pro Transaktion ausgeführt werden. Es gibt keine praktische Begrenzung für AFAIK, aber durch Batching können Sie einen Fehler beheben, indem Sie den Start jedes Batches in Ihren Eingabedaten markieren. Wieder scheinen Sie dies bereits zu tun.
Verwenden Sie
synchronous_commit=off
und eine enormecommit_delay
, um fsync () Kosten zu reduzieren. Dies hilft jedoch nicht viel, wenn Sie Ihre Arbeit in große Transaktionen zusammengefasst haben.INSERT
oderCOPY
parallel von mehreren Verbindungen. Wie viele davon hängen vom Festplattensubsystem Ihrer Hardware ab. Als Faustregel gilt, dass Sie eine Verbindung pro physischer Festplatte benötigen, wenn Sie direkt angeschlossenen Speicher verwenden.Stellen Sie einen hohen
checkpoint_segments
Wert ein und aktivieren Sielog_checkpoints
. Sehen Sie sich die PostgreSQL-Protokolle an und stellen Sie sicher, dass Sie sich nicht über zu häufig auftretende Checkpoints beschweren.Wenn und nur wenn es Ihnen nichts ausmacht, Ihren gesamten PostgreSQL-Cluster (Ihre Datenbank und alle anderen im selben Cluster) durch katastrophale Beschädigung zu verlieren, wenn das System während des Imports abstürzt, können Sie Pg stoppen, festlegen
fsync=off
, Pg starten, Ihren Import durchführen, dann (lebenswichtig) Pg stoppen undfsync=on
erneut einstellen . Siehe WAL-Konfiguration . Tun Sie dies nicht, wenn sich in einer Datenbank Ihrer PostgreSQL-Installation bereits Daten befinden, die Sie interessieren. Wenn Sie einstellenfsync=off
, können Sie auch einstellenfull_page_writes=off
; Denken Sie auch hier daran, es nach dem Import wieder einzuschalten, um eine Beschädigung der Datenbank und Datenverlust zu vermeiden. Siehe nicht dauerhafte Einstellungen im Pg-Handbuch.Sie sollten sich auch die Optimierung Ihres Systems ansehen:
Verwenden Sie so viel wie möglich hochwertige SSDs für die Speicherung. Gute SSDs mit zuverlässigen, stromgeschützten Rückschreibcaches beschleunigen die Festschreibungsraten erheblich. Sie sind weniger nützlich, wenn Sie den obigen Ratschlägen folgen - was das Löschen der Festplatte / die Anzahl der
fsync()
s verringert -, können aber dennoch eine große Hilfe sein. Verwenden Sie keine billigen SSDs ohne angemessenen Stromausfallschutz, es sei denn, Sie möchten Ihre Daten nicht aufbewahren.Wenn Sie RAID 5 oder RAID 6 für direkt angeschlossenen Speicher verwenden, beenden Sie jetzt. Sichern Sie Ihre Daten, strukturieren Sie Ihr RAID-Array auf RAID 10 um und versuchen Sie es erneut. RAID 5/6 ist für die Massenschreibleistung hoffnungslos - obwohl ein guter RAID-Controller mit einem großen Cache helfen kann.
Wenn Sie die Option haben, einen Hardware-RAID-Controller mit einem großen batteriegepufferten Rückschreibcache zu verwenden, kann dies die Schreibleistung für Workloads mit vielen Commits erheblich verbessern. Es hilft nicht so viel, wenn Sie ein asynchrones Commit mit einem commit_delay verwenden oder wenn Sie während des Massenladens weniger große Transaktionen ausführen.
Wenn möglich, speichern Sie WAL (
pg_xlog
) auf einer separaten Festplatte / einem separaten Festplattenarray. Es macht wenig Sinn, ein separates Dateisystem auf derselben Festplatte zu verwenden. Menschen entscheiden sich oft dafür, ein RAID1-Paar für WAL zu verwenden. Dies hat wiederum größere Auswirkungen auf Systeme mit hohen Festschreibungsraten und hat nur geringe Auswirkungen, wenn Sie eine nicht protokollierte Tabelle als Datenladeziel verwenden.Möglicherweise interessieren Sie sich auch für die Optimierung von PostgreSQL für schnelle Tests .
quelle
indisvalid
( postgresql.org/docs/8.3/static/catalog-pg-index.html ) auf false setzen, dann Daten laden und dann Indizes online schaltenREINDEX
?UNLOGGED
? Ein schneller Test zeigt eine Verbesserung um 10-20%.Die Verwendung
COPY table TO ... WITH BINARY
gemäß der Dokumentation ist " etwas schneller als die Text- und CSV-Formate ". 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
Neben dem hervorragenden Beitrag von Craig Ringer und dem Blog-Beitrag von depesz müssen Sie einige zusätzliche Dinge tun, um Ihre Einfügungen über die ODBC- Schnittstelle ( psqlodbc ) mithilfe von Einfügungen mit vorbereiteten Anweisungen innerhalb einer Transaktion zu beschleunigen schnell arbeiten:
Protocol=-1
in der Verbindungszeichenfolge angeben. Standardmäßig verwendet psqlodbc die Ebene "Anweisung", wodurch für jede Anweisung ein SAVEPOINT erstellt wird und nicht für eine gesamte Transaktion, wodurch Einfügungen langsamer werden.UseServerSidePrepare=1
in der Verbindungszeichenfolge angeben. Ohne diese Option sendet der Client die gesamte Einfügeanweisung zusammen mit jeder eingefügten Zeile.SQLSetConnectAttr(conn, SQL_ATTR_AUTOCOMMIT, reinterpret_cast<SQLPOINTER>(SQL_AUTOCOMMIT_OFF), 0);
SQLEndTran(SQL_HANDLE_DBC, conn, SQL_COMMIT);
. Es ist nicht erforderlich, eine Transaktion explizit zu öffnen.Leider "implementiert" psqlodbc,
SQLBulkOperations
indem es eine Reihe unvorbereiteter Einfügeanweisungen ausgibt , so dass zum Erreichen der schnellsten Einfügung die obigen Schritte manuell codiert werden müssen.quelle
A8=30000000
in der Verbindungszeichenfolge sollte auch verwendet werden, um Einfügungen zu beschleunigen.Ich habe heute ungefähr 6 Stunden mit dem gleichen Thema verbracht. Die Einfügungen werden mit einer "normalen" Geschwindigkeit (weniger als 3 Sekunden pro 100 KB) bis zu 5MI (von insgesamt 30MI) Zeilen ausgeführt, und dann sinkt die Leistung drastisch (bis auf 1 Minute pro 100K).
Ich werde nicht alle Dinge auflisten, die nicht funktioniert haben und direkt zum Fleisch schneiden.
Ich habe einen Primärschlüssel in der Zieltabelle abgelegt (die eine GUID war), und meine 30MI oder Zeilen flossen glücklich mit einer konstanten Geschwindigkeit von weniger als 3 Sekunden pro 100 KB an ihr Ziel.
quelle
Wenn Sie zufällig Spalten mit UUIDs einfügen (was nicht genau Ihr Fall ist) und zur @ Tennis- Antwort hinzufügen möchten (ich kann noch keinen Kommentar abgeben), raten Sie, als gen_random_uuid () zu verwenden (erfordert PG 9.4 und das Modul pgcrypto) (a lot) schneller als uuid_generate_v4 ()
vs.
Es ist auch der vorgeschlagene offizielle Weg, dies zu tun
Dadurch wurde die Einfügezeit für 3,7 Millionen Zeilen von ~ 2 Stunden auf ~ 10 Minuten gesenkt.
quelle
Deaktivieren Sie für eine optimale Einfügeleistung den Index, wenn dies für Sie eine Option ist. Ansonsten ist auch eine bessere Hardware (Festplatte, Speicher) hilfreich
quelle
Ich habe auch dieses Problem mit der Einfügungsleistung festgestellt. Meine Lösung besteht darin, einige Go-Routinen zu erstellen, um die Einfügearbeiten abzuschließen. In der Zwischenzeit
SetMaxOpenConns
sollte eine richtige Nummer angegeben werden, da sonst zu viele offene Verbindungsfehler gemeldet werden.Die Ladegeschwindigkeit ist für mein Projekt viel schneller. Dieses Code-Snippet gab nur eine Idee, wie es funktioniert. Leser sollten es leicht ändern können.
quelle