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

Wie funktioniert COPY und warum ist es so viel schneller als INSERT?

Hier spielen eine Reihe von Faktoren eine Rolle:

  • Netzwerklatenz und Roundtrip-Verzögerungen
  • Overheads pro Anweisung in PostgreSQL
  • Kontextwechsel und Planerverzögerungen
  • COMMIT Kosten, wenn für Leute, die einen Commit pro Insert machen (Sie nicht)
  • COPY -spezifische Optimierungen für das Massenladen

Netzwerklatenz

Wenn der Server entfernt ist, "bezahlen" Sie möglicherweise einen festen "Preis" pro Anweisung von beispielsweise 50 ms (1/20 Sekunde). Oder viel mehr für einige Cloud-gehostete DBs. Da die nächste Einfügung erst beginnen kann, wenn die letzte erfolgreich abgeschlossen wurde, bedeutet dies Ihr Maximum Die Rate der Einfügungen beträgt 1000/Round-Trip-Latenz in ms Zeilen pro Sekunde. Bei einer Latenz von 50 ms ("Ping-Zeit") sind das 20 Zeilen/Sekunde. Selbst auf einem lokalen Server ist diese Verzögerung ungleich Null. Wohingegen COPY füllt einfach die TCP-Sende- und -Empfangsfenster und streamt Zeilen so schnell, wie die DB sie schreiben und das Netzwerk sie übertragen kann. Es wird nicht stark von der Latenz beeinflusst und kann Tausende von Zeilen pro Sekunde auf derselben Netzwerkverbindung einfügen.

Kosten pro Anweisung in PostgreSQL

Es fallen auch Kosten für das Parsen, Planen und Ausführen einer Anweisung in PostgreSQL an. Es muss Sperren nehmen, Beziehungsdateien öffnen, Indizes nachschlagen usw. COPY versucht, all dies zu Beginn einmal zu tun und sich dann nur darauf zu konzentrieren, Zeilen so schnell wie möglich zu laden.

Aufgaben-/Kontextwechselkosten

Es fallen weitere Zeitkosten an, da das Betriebssystem zwischen Postgres wechseln muss, das auf eine Zeile wartet, während Ihre App diese vorbereitet und sendet, und Ihrer App, die auf die Antwort von Postgres wartet, während Postgres die Zeile verarbeitet. Jedes Mal, wenn Sie von einem zum anderen wechseln, verschwenden Sie ein wenig Zeit. Es wird potenziell mehr Zeit damit verschwendet, verschiedene Low-Level-Kernel-Zustände auszusetzen und wieder aufzunehmen, wenn Prozesse in Wartezustände eintreten und diese verlassen.

Verpassen von COPY-Optimierungen

Darüber hinaus COPY hat einige Optimierungen, die es für einige Arten von Lasten verwenden kann. Wenn es keinen generierten Schlüssel gibt und alle Standardwerte beispielsweise Konstanten sind, kann es sie vorberechnen und den Executor vollständig umgehen, indem Daten schnell auf einer niedrigeren Ebene in die Tabelle geladen werden, wodurch ein Teil der normalen Arbeit von PostgreSQL vollständig übersprungen wird. Wenn Sie CREATE TABLE oder TRUNCATE in derselben Transaktion COPY , kann es noch mehr Tricks anwenden, um das Laden zu beschleunigen, indem es die normale Transaktionsbuchhaltung umgeht, die in einer Multi-Client-Datenbank benötigt wird.

Trotzdem ist COPY von PostgreSQL könnte noch viel mehr tun, um die Dinge zu beschleunigen, Dinge, die es noch nicht kann. Es könnte Indexaktualisierungen automatisch überspringen und dann Indizes neu erstellen, wenn Sie mehr als einen bestimmten Teil der Tabelle ändern. Es könnte Indexaktualisierungen in Stapeln durchführen. Vieles mehr.

Kosten festlegen

Eine letzte zu berücksichtigende Sache sind die Commit-Kosten. Es ist wahrscheinlich kein Problem für Sie, weil psycopg2 öffnet standardmäßig eine Transaktion und verpflichtet sich erst, wenn Sie es dazu auffordern. Es sei denn, Sie haben ihm gesagt, dass es Autocommit verwenden soll. Aber für viele DB-Treiber ist Autocommit die Standardeinstellung. In solchen Fällen würden Sie für jedes INSERT einen Commit durchführen . Das bedeutet eine Festplattenspülung, bei der der Server sicherstellt, dass er alle Daten im Speicher auf die Festplatte schreibt und die Festplatten anweist, ihre eigenen Caches in den persistenten Speicher zu schreiben. Dies kann lang dauern Zeit und variiert stark je nach Hardware. Mein SSD-basierter NVMe-BTRFS-Laptop kann nur 200 fsyncs/Sekunde ausführen, gegenüber 300.000 nicht synchronisierten Schreibvorgängen/Sekunde. Es werden also nur 200 Zeilen/Sekunde geladen! Einige Server können nur 50 fsyncs/Sekunde ausführen. Manche schaffen 20.000. Wenn Sie also regelmäßig festschreiben müssen, versuchen Sie, in Stapeln zu laden und festzuschreiben, mehrzeilige Einfügungen vorzunehmen usw. Weil COPY nur ein Commit am Ende, Commit-Kosten sind vernachlässigbar. Das bedeutet aber auch COPY kann sich nicht von Fehlern auf halbem Weg durch die Daten erholen; es macht den gesamten Massenladevorgang rückgängig.