it-swarm.com.de

Aktualisiert das Aktualisieren einer Zeile mit demselben Wert die Zeile tatsächlich?

Ich habe eine leistungsbezogene Frage. Angenommen, ich habe einen Benutzer mit dem Vornamen Michael. Nehmen Sie die folgende Abfrage:

UPDATE users
SET first_name = 'Michael'
WHERE users.id = 123

Wird die Abfrage das Update tatsächlich ausführen, obwohl es auf denselben Wert aktualisiert wird? Wenn ja, wie kann ich dies verhindern?

32
OneSneakyMofo

Aufgrund des MVCC-Modells von Postgres und gemäß den Regeln von SQL schreibt ein UPDATE eine neue Zeilenversion für every Zeile, die dies nicht ist in der WHERE -Klausel ausgeschlossen.

Dies tut hat einen mehr oder weniger wesentlichen Einfluss auf die Leistung, direkt und indirekt. "Leere Updates" haben die gleichen Kosten pro Zeile wie jedes andere Update. Sie lösen Trigger (falls vorhanden) wie jedes andere Update aus, sie müssen WAL-protokolliert sein und sie erzeugen tote Zeilen, die die Tabelle aufblähen und später wie jedes andere Update mehr Arbeit für VACUUM verursachen .

Indiziert Einträge und TOASTed Spalten, in denen keine der beteiligten Spalten geändert wird can bleiben gleich, dies gilt jedoch für jede aktualisierte Zeile. Verbunden:

Es ist fast immer eine gute Idee, solche leeren Updates auszuschließen (wenn es tatsächlich möglich ist). Sie haben in Ihrer Frage keine Tabellendefinition angegeben (was immer eine gute Idee ist). Wir müssen davon ausgehen, dass first_name NULL sein kann (was für einen "Vornamen" nicht überraschend wäre), daher muss die Abfrage NULL-safe verwenden Vergleich :

UPDATE users
SET    first_name = 'Michael'
WHERE  id = 123
AND   first_name IS DISTINCT FROM 'Michael';

Wenn first_name IS NULL Vor dem Update, würde ein Test mit nur first_name <> 'Michael' NULL ergeben und als solches die Zeile vom Update ausschließen. Hinterhältiger Fehler. If Die Spalte ist definiert NOT NULL , verwenden Sie die einfache Gleichheit Überprüfen Sie jedoch, weil das ein bisschen billiger ist.

Verbunden:

38

ORMs wie Ruby auf Rails Angebot verzögerte Ausführung, die einen Datensatz als geändert markieren (oder nicht) und dann bei Bedarf oder Aufruf die Änderung an die Datenbank senden.

PostgreSQL ist eine Datenbank und kein ORM. Es hätte die Leistung verringert, wenn es Zeit gekostet hätte, zu überprüfen, ob ein neuer Wert mit dem aktualisierten Wert in Ihrer Abfrage übereinstimmt.

Der Wert wird daher unabhängig davon aktualisiert, ob er mit dem neuen Wert identisch ist oder nicht.

Wenn Sie dies verhindern möchten, können Sie Code verwenden, wie Max Vernon in seiner Antwort vorgeschlagen hat.

4
Thronk

Sie können einfach die where -Klausel hinzufügen:

UPDATE users
SET first_name = 'Michael'
WHERE users.id = 123
    AND (first_name <> 'Michael' OR first_name IS NULL);

Wenn first_name ist definiert als NOT NULL, das OR first_name IS NULL Teil kann entfernt werden.

Die Bedingung:

(first_name <> 'Michael' OR first_name IS NULL)

kann auch eleganter geschrieben werden als (in Erwins Antwort):

first_name IS DISTINCT FROM 'Michael'
2
Max Vernon

Aus Datenbanksicht

Die Antwort auf Ihre Frage lautet JA. Das Update wird stattfinden. Die Datenbank überprüft nicht den vorherigen Wert, sondern legt nur den neuen Wert fest.

Da dies im Speicher geschieht (und erst nach einem Commit in die Datendateien geschrieben wird), ist die Leistung kein Problem.

Aus ORM-Sicht

Normalerweise haben Sie ein Objekt, das eine einzelne Zeile der Datenbank darstellt (es kann viel komplexer sein, aber lassen Sie es uns einfach halten). Dieses Objekt wird im Speicher (auf App-Server-Ebene) verwaltet, und nur die letzte festgeschriebene Version dieses Objekts schafft es zu einem bestimmten Zeitpunkt tatsächlich in die Datenbank.

Das könnte das unterschiedliche Verhalten erklären.

Vergleichen wir jetzt kein Frachtschiff mit einem 3D-Drucker. Die Tatsache, dass Sie 3D-Drucker mit Frachtschiffen versenden können, bedeutet nicht, dass es einen Vergleich zwischen ihnen geben kann.

Genießen!

Ich hoffe, dies hat einige Konzepte geklärt.

1
Silvarion