PostgreSQL-Antipatterns: Kämpfen gegen die Horden der "Untoten"

Die Funktionsweise der internen Mechanismen von PostgreSQL ermöglicht es, in bestimmten Situationen sehr schnell zu sein und in anderen weniger. Heute betrachten wir ein klassisches Beispiel für den Konflikt zwischen der Funktionsweise der Datenbank und dem, was ein Entwickler damit tut — UPDATE vs MVCC-Prinzipien.

Umreißen wir die Handlung aus einem ausgezeichneten Artikel:

Wenn eine Zeile mit dem Befehl UPDATE geändert wird, erfolgen tatsächlich zwei Operationen: DELETE und INSERT. Bei der aktuellen Version der Zeile wird xmax auf die Transaktionsnummer gesetzt, die das UPDATE ausgeführt hat. Anschließend wird eine neue Version derselben Zeile erstellt; der Wert von xmin entspricht dem xmax der vorherigen Version.

Nach Abschluss dieser Transaktion werden die alte oder neue Version, je nach COMMIT/ROLLBACK, als „tot“ (dead tuples) oder beim Durchlauf VACUUM in der Tabelle erkannt und bereinigt.

PostgreSQL-Antipatterns: Kämpfen gegen die Horden der "Untoten"

Dies geschieht jedoch nicht sofort, während Probleme mit „Toten“ sehr schnell auftreten können — insbesondere bei mehrfachen oder massiven Aktualisierungen von Datensätzen in einer großen Tabelle. Später könnte man dann feststellen, dass selbst VACUUM nicht helfen kann..

#1: I Like To Move It

Angenommen, Ihre Methode in der Geschäftslogik arbeitet einwandfrei, und plötzlich merkt sie, dass das Feld X in einem bestimmten Datensatz aktualisiert werden muss:

UPDATE tbl SET X =  WHERE pk = $1;

Dann stellt sich während der Ausführung heraus, dass auch das Feld Y aktualisiert werden sollte:

UPDATE tbl SET Y =  WHERE pk = $1;

… und dann noch Z – warum sich damit aufhalten?

UPDATE tbl SET Z =  WHERE pk = $1;

Wie viele Versionen dieses Datensatzes haben wir nun in der Datenbank? Aha, 4 Stück! Davon ist eine aktuell, und 3 müssen Sie durch [auto]VACUUM entfernen.

Das brauchen Sie nicht! Nutzen Sie die Aktualisierung aller Felder in einer Anfrage – fast immer lässt sich die Logik des Verfahrens so ändern:

UPDATE tbl SET X = , Y = , Z =  WHERE pk = $1;

#2: Use IS DISTINCT FROM, Luke!

Also, Sie möchten tatsächlich viele Einträge in der Tabelle aktualisieren (zum Beispiel während der Anwendung eines Skripts oder Konverters). Und das Skript enthält etwa dies:

UPDATE tbl SET X =  WHERE pk BETWEEN $1 AND $2;

Etwa in dieser Form taucht die Anfrage häufig auf und fast immer nicht, um ein neues leeres Feld zu füllen, sondern um einige Fehler in den Daten zu korrigieren. Dabei wird die Korrektheit der bereits vorhandenen Daten überhaupt nicht berücksichtigt – und das ist ein Fehler! Das heißt, der Datensatz wird überschrieben, selbst wenn genau das, was gewünscht war, drinstand – aber warum? Korrigieren wir das:

UPDATE tbl SET X =  WHERE pk BETWEEN $1 AND $2 AND X IS DISTINCT FROM ;

Viele wissen nicht von der Existenz dieses großartigen Operators, deshalb hier eine kurze Zusammenfassung von IS DISTINCT FROM und anderen logischen Operatoren zur Hilfe:
PostgreSQL-Antipatterns: Kämpfen gegen die Horden der "Untoten"
… und ein wenig über Operationen mit komplexen ROW()-Ausdrücken:
PostgreSQL-Antipatterns: Kämpfen gegen die Horden der "Untoten"

#3: А я милого узнаю по… блокировке

Es werden zwei identische parallele Prozesse gestartet,von denen jeder versucht, den Eintrag als „in Bearbeitung“ zu kennzeichnen:

UPDATE tbl SET processing = TRUE WHERE pk = $1;

Selbst wenn diese Prozesse unabhängig voneinander handeln, blockiert der zweite Client bei dieser Abfrage, solange die erste Transaktion nicht abgeschlossen ist.

Lösung Nr. 1: Die Aufgabe reduziert sich auf das Vorherige.

Fügen wir einfach wieder hinzu: IS DISTINCT FROM:

UPDATE tbl SET processing = TRUE WHERE pk = $1 AND processing IS DISTINCT FROM TRUE;

In dieser Form wird die zweite Abfrage in der Datenbank einfach nichts ändern, da dort bereits „alles in Ordnung“ ist – daher wird keine Sperre auftreten. Das Fehlen des Eintrags wird dann im Anwendungsalgorithmus behandelt.

Lösung Nr. 2: Advisory Locks

Ein großes Thema für einen separaten Artikel, in dem man mehr über Anwendungsarten und „Hürden“ von Advisory Locks lesen kann..

Lösung Nr. 3: sinnlose Aufrufe

Hier sollte auf jeden Fall etwas geschehen. gleichzeitiger Zugriff auf denselben Datensatz? Или вы все-таки накосячили с алгоритмами вызовов бизнес-логики со стороны клиента, например? А если подумать?..

Quelle: habr.com

Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen 🔥 Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen | ProHoster