PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

7 Best-Practice-Tipps für das Laden von PostgreSQL-Massendaten

Manchmal müssen PostgreSQL-Datenbanken große Datenmengen in einem einzigen oder einer minimalen Anzahl von Schritten importieren. Dies wird allgemein als Massendatenimport bezeichnet, wobei die Datenquelle in der Regel aus einer oder mehreren großen Dateien besteht. Dieser Vorgang kann manchmal unannehmbar langsam sein.

Es gibt viele Gründe für eine solche schlechte Leistung:Indizes, Trigger, Fremdschlüssel, GUID-Primärschlüssel oder sogar das Write Ahead Log (WAL) können Verzögerungen verursachen.

In diesem Artikel behandeln wir einige Best-Practice-Tipps für den Massenimport von Daten in PostgreSQL-Datenbanken. Es kann jedoch Situationen geben, in denen keiner dieser Tipps eine effiziente Lösung darstellt. Wir empfehlen den Lesern, die Vor- und Nachteile jeder Methode abzuwägen, bevor sie sie anwenden.

Tipp 1:Ändern Sie die Zieltabelle in den nicht protokollierten Modus

Für PostgreSQL 9.5 und höher kann die Zieltabelle zuerst auf UNLOGGED und dann wieder auf LOGGED geändert werden, sobald die Daten geladen sind:

ALTER TABLE <target table> SET UNLOGGED
<bulk data insert operations…>
ALTER TABLE <target table> LOGGED

Der UNLOGGED-Modus stellt sicher, dass PostgreSQL keine Tabellenschreibvorgänge an das Write Ahead Log (WAL) sendet. Dies kann den Ladevorgang erheblich beschleunigen. Da die Vorgänge jedoch nicht protokolliert werden, können Daten nicht wiederhergestellt werden, wenn es während des Ladevorgangs zu einem Absturz oder unsauberen Herunterfahren des Servers kommt. PostgreSQL kürzt automatisch alle nicht protokollierten Tabellen, sobald es neu gestartet wird.

Außerdem werden nicht protokollierte Tabellen nicht auf Standby-Server repliziert. In solchen Fällen müssen vorhandene Replikationen vor dem Laden entfernt und nach dem Laden neu erstellt werden. Abhängig von der Datenmenge im primären Knoten und der Anzahl der Standbys kann die Zeit für die Wiederherstellung der Replikation ziemlich lang sein und aufgrund von Hochverfügbarkeitsanforderungen nicht akzeptabel sein.

Wir empfehlen die folgenden Best Practices für das Masseneinfügen von Daten in nicht protokollierte Tabellen:

  • Erstellen einer Sicherungskopie der Tabelle und der Daten, bevor sie in einen nicht protokollierten Modus geändert werden
  • Wiederherstellung jeglicher Replikation auf Standby-Servern, sobald das Laden der Daten abgeschlossen ist
  • Verwenden von nicht protokollierten Masseneinfügungen für Tabellen, die leicht neu gefüllt werden können (z. B. große Nachschlagetabellen oder Dimensionstabellen)

Tipp 2:Indizes löschen und neu erstellen

Vorhandene Indizes können beim Einfügen von Massendaten zu erheblichen Verzögerungen führen. Dies liegt daran, dass beim Hinzufügen jeder Zeile auch der entsprechende Indexeintrag aktualisiert werden muss.

Wir empfehlen, nach Möglichkeit Indizes in der Zieltabelle zu löschen, bevor Sie mit der Masseneinfügung beginnen, und die Indizes nach Abschluss des Ladevorgangs neu zu erstellen. Auch hier kann das Erstellen von Indizes für große Tabellen zeitaufwändig sein, ist aber im Allgemeinen schneller als das Aktualisieren der Indizes während des Ladens.

DROP INDEX <index_name1>, <index_name2> … <index_name_n>
<bulk data insert operations…>
CREATE INDEX <index_name> ON <target_table>(column1, …,column n)

Es kann sich lohnen, den maintenance_work_mem vorübergehend zu erhöhen Konfigurationsparameter kurz vor dem Erstellen der Indizes. Der erhöhte Arbeitsspeicher kann dabei helfen, die Indizes schneller zu erstellen.

Eine weitere Möglichkeit, auf Nummer sicher zu gehen, besteht darin, eine Kopie der Zieltabelle in derselben Datenbank mit vorhandenen Daten und Indizes zu erstellen. Diese neu kopierte Tabelle kann dann mit Masseneinfügung für beide Szenarien getestet werden:Indizes löschen und neu erstellen oder sie dynamisch aktualisieren. Die Methode, die eine bessere Leistung liefert, kann dann für die Live-Tabelle befolgt werden.

Tipp 3:Fremdschlüssel löschen und neu erstellen

Wie Indizes können sich auch Fremdschlüsseleinschränkungen auf die Massenladeleistung auswirken. Denn jeder Fremdschlüssel in jeder eingefügten Zeile muss auf die Existenz eines entsprechenden Primärschlüssels geprüft werden. Hinter den Kulissen verwendet PostgreSQL einen Trigger, um die Überprüfung durchzuführen. Beim Laden einer großen Anzahl von Zeilen muss dieser Trigger für jede Zeile ausgelöst werden, was den Overhead erhöht.

Sofern nicht durch Geschäftsregeln eingeschränkt, empfehlen wir, alle Fremdschlüssel aus der Zieltabelle zu löschen, die Daten in einer einzigen Transaktion zu laden und die Fremdschlüssel nach dem Festschreiben der Transaktion neu zu erstellen.

ALTER TABLE <target_table> 
DROP CONSTRAINT <foreign_key_constraint>

BEGIN TRANSACTION
<bulk data insert operations…>
COMMIT

ALTER TABLE <target_table> 
ADD CONSTRAINT <foreign key constraint>  
FOREIGN KEY (<foreign_key_field>) 
REFERENCES <parent_table>(<primary key field>)...

Erhöhen Sie erneut den maintenance_work_mem Konfigurationsparameter kann die Leistung beim Neuerstellen von Fremdschlüsseleinschränkungen verbessern.

Tipp 4:Trigger deaktivieren

INSERT- oder DELETE-Trigger (wenn der Ladeprozess auch das Löschen von Datensätzen aus der Zieltabelle umfasst) können Verzögerungen beim Laden von Massendaten verursachen. Dies liegt daran, dass jeder Trigger über eine Logik verfügt, die überprüft werden muss, und Operationen, die unmittelbar nach dem Einfügen oder Löschen jeder Zeile abgeschlossen werden müssen.

Wir empfehlen, alle Trigger in der Zieltabelle vor dem Massenladen von Daten zu deaktivieren und sie nach Abschluss des Ladevorgangs zu aktivieren. Das Deaktivieren ALLER Trigger umfasst auch Systemtrigger, die Fremdschlüssel-Einschränkungsprüfungen erzwingen.

ALTER TABLE <target table> DISABLE TRIGGER ALL
<bulk data insert operations…>
ALTER TABLE <target table> ENABLE TRIGGER ALL

Tipp 5:Verwenden Sie den COPY-Befehl

Wir empfehlen die Verwendung von PostgreSQL COPY Befehl zum Laden von Daten aus einer oder mehreren Dateien. COPY ist für das Laden von Massendaten optimiert. Es ist effizienter, als eine große Anzahl von INSERT-Anweisungen oder sogar mehrwertigen INSERTS auszuführen.

COPY <target table> [( column1>, … , <column_n>)]
FROM  '<file_name_and_path>' 
WITH  (<option1>, <option2>, … , <option_n>)

Weitere Vorteile der Verwendung von COPY sind:

  • Es unterstützt sowohl den Import von Text- als auch Binärdateien
  • Es ist transaktionaler Natur
  • Es ermöglicht die Angabe der Struktur der Eingabedateien
  • Es kann Daten unter Verwendung einer WHERE-Klausel bedingt laden

Tipp 6:Verwenden Sie mehrwertiges INSERT

Das Ausführen mehrerer tausend oder mehrerer hunderttausend INSERT-Anweisungen kann eine schlechte Wahl für das Laden von Massendaten sein. Das liegt daran, dass jeder einzelne INSERT-Befehl vom Abfrageoptimierer analysiert und vorbereitet werden muss, alle Constraint-Prüfungen durchlaufen, als separate Transaktion ausgeführt und in der WAL protokolliert werden muss. Die Verwendung einer mehrwertigen einzelnen INSERT-Anweisung kann diesen Overhead einsparen.

INSERT INTO <target_table> (<column1>, <column2>, …, <column_n>) 
VALUES 
(<value a>, <value b>, …, <value x>),
(<value 1>, <value 2>, …, <value n>),
(<value A>, <value B>, …, <value Z>),
(<value i>, <value ii>, …, <value L>),
...

Die Leistung von mehrwertigem INSERT wird durch vorhandene Indizes beeinflusst. Wir empfehlen, die Indizes vor dem Ausführen des Befehls zu löschen und die Indizes danach neu zu erstellen.

Ein weiterer zu beachtender Bereich ist die Menge an Speicher, die PostgreSQL zum Ausführen mehrwertiger INSERTs zur Verfügung steht. Wenn ein mehrwertiges INSERT ausgeführt wird, muss eine große Anzahl von Eingabewerten in den RAM passen, und wenn nicht genügend Speicher verfügbar ist, kann der Prozess fehlschlagen.

Wir empfehlen, die effektive_cache_size festzulegen Parameter auf 50 % und shared_buffer Parameter auf 25 % des gesamten Arbeitsspeichers der Maschine. Um sicherzugehen, führt es außerdem eine Reihe von mehrwertigen INSERTs aus, wobei jede Anweisung Werte für 1000 Zeilen enthält.

Tipp 7:Führen Sie ANALYZE durch

Dies hat nichts mit der Verbesserung der Leistung des Massendatenimports zu tun, aber wir empfehlen dringend, ANALYZE auszuführen Befehl auf der Zieltabelle unmittelbar nach der Massenimport. Eine große Anzahl neuer Zeilen verzerrt die Datenverteilung in Spalten erheblich und führt dazu, dass alle vorhandenen Statistiken in der Tabelle veraltet sind. Wenn der Abfrageoptimierer veraltete Statistiken verwendet, kann die Abfrageleistung unannehmbar schlecht sein. Durch Ausführen des Befehls ANALYZE wird sichergestellt, dass alle vorhandenen Statistiken aktualisiert werden.

Abschließende Gedanken

Der Massendatenimport findet für eine Datenbankanwendung möglicherweise nicht jeden Tag statt, aber es gibt eine Auswirkung auf die Leistung von Abfragen, wenn sie ausgeführt werden. Deshalb ist es notwendig, die Ladezeit so gut wie möglich zu minimieren. Eine Sache, die DBAs tun können, um Überraschungen zu minimieren, besteht darin, die Lastoptimierungen in einer Entwicklungs- oder Staging-Umgebung mit ähnlichen Serverspezifikationen und PostgreSQL-Konfigurationen zu testen. Jedes Datenladeszenario ist anders, und es ist am besten, jede Methode auszuprobieren und diejenige zu finden, die funktioniert.