PostgreSQL: Unveränderlich, flüchtig, stabil

11

Ich bin mir nicht sicher, welche Bedeutung die Definitionen für die Funktionen IMMUTABLE, VOLATILE und STABLE haben.

Ich habe die Dokumentation gelesen, insbesondere die Definitionen der einzelnen.

IMMUTABLE gibt an, dass die Funktion die Datenbank nicht ändern kann und immer das gleiche Ergebnis zurückgibt, wenn dieselben Argumentwerte angegeben werden . Das heißt, es werden keine Datenbanksuchen durchgeführt oder Informationen verwendet, die nicht direkt in der Argumentliste enthalten sind. Wenn diese Option angegeben ist, kann jeder Aufruf der Funktion mit allen Konstantenargumenten sofort durch den Funktionswert ersetzt werden.

STABLE gibt an, dass die Funktion die Datenbank nicht ändern kann und dass sie innerhalb eines einzelnen Tabellenscans konsistent dasselbe Ergebnis für dieselben Argumentwerte zurückgibt , dass sich das Ergebnis jedoch über SQL-Anweisungen hinweg ändern kann. Dies ist die geeignete Auswahl für Funktionen, deren Ergebnisse von Datenbanksuchen, Parametervariablen (z. B. der aktuellen Zeitzone) usw. abhängen. (Dies ist nicht für AFTER-Trigger geeignet, die vom aktuellen Befehl geänderte Zeilen abfragen möchten.) Beachten Sie außerdem, dass die Die Funktionsfamilie current_timestamp gilt als stabil, da sich ihre Werte innerhalb einer Transaktion nicht ändern.

VOLATILE gibt an, dass sich der Funktionswert auch innerhalb eines einzelnen Tabellenscans ändern kann, sodass keine Optimierungen vorgenommen werden können. Relativ wenige Datenbankfunktionen sind in diesem Sinne flüchtig; Einige Beispiele sind random (), currval (), timeofday (). Beachten Sie jedoch, dass jede Funktion mit Nebenwirkungen als volatil eingestuft werden muss, auch wenn das Ergebnis durchaus vorhersehbar ist, um zu verhindern, dass Anrufe wegoptimiert werden. Ein Beispiel ist setval ().

Meine Verwirrung kommt mit der Bedingung für IMMUTABLE und STABLE, dass die Funktion IMMER oder KONSISTENT das gleiche Ergebnis mit den gleichen Argumenten zurückgibt.

Die IMMUTABLE-Definition besagt, dass die Funktion keine Datenbanksuchen durchführt oder Informationen verwendet, die nicht direkt in ihrer Argumentliste enthalten sind. Für mich bedeutet dies, dass solche Funktionen zum Manipulieren der vom Client bereitgestellten Daten verwendet werden und keine SELECT-Anweisungen enthalten sollten ... obwohl das für mich nur ein bisschen seltsam klingt.

Bei STABLE ist die Definition insofern ähnlich, als sie besagt, dass konsistent dasselbe Ergebnis zurückgegeben werden soll. Für mich bedeutet dies, dass die Funktion jedes Mal, wenn sie mit denselben Argumenten aufgerufen wird, dieselben Ergebnisse zurückgeben sollte (jedes Mal dieselben exakten Zeilen).

Für mich bedeutet dies, dass jede Funktion, die ein SELECT für eine Tabelle oder Tabellen ausführt, die aktualisiert werden können, nur flüchtig sein sollte.

Aber wieder ... das klingt für mich nicht richtig.

Um dies auf meinen Anwendungsfall zurückzuführen, schreibe ich Funktionen, die SELECT-Anweisungen mit mehreren JOINs für Tabellen ausführen, die ständig hinzugefügt werden. Daher wird erwartet, dass die Funktionsaufrufe bei jedem Aufruf unterschiedliche Ergebnisse zurückgeben, selbst mit denselben Argumenten .

Bedeutet das also, dass meine Funktionen VOLATIL sein sollten? Auch wenn aus der Dokumentation hervorgeht, dass relativ wenige Datenbankfunktionen in diesem Sinne flüchtig sind ?

Danke!

Brooks
quelle

Antworten:

15

IMMUTABLEmuss eine reine Funktion sein, deren Ergebnisse nur von ihren Eingaben abhängen . Dies ist eine sehr strenge Anforderung; Sie können keine anderen nicht unveränderlichen Funktionen aufrufen, sie können nicht auf Tabellen zugreifen, sie können nicht auf den Wert von Konfigurationseigenschaften zugreifen usw.

STABLEkann alle Eingaben verwenden, die selbst sind STABLE: andere STABLEoder IMMUTABLEFunktionen und SELECTAbfragen von Tabellen. Das Abfragen von Tabellen ist sicher, da sich die Ansicht der Funktion dieser Tabellen im aktuellen Snapshot der Abfrage nicht ändert. Sie können auf GUC-Werte ( current_setting(...)) zugreifen , solange Sie wissen, dass sie nicht auch in der aktuellen Anweisung zugewiesen werden.

VOLATILE Funktionen sind alles, was nicht zu den oben genannten passt:

  • Alles mit Nebenwirkungen
  • Alles was schreibt
  • Alles, was externe Daten abfragt, die nicht vom PostgreSQL-Snapshot verwaltet werden
  • ...

Im Allgemeinen lassen VOLATILESie einfach alles, es sei denn, Sie haben einen guten Grund, dies nicht zu tun.

Der Hauptgrund für die Verwendung IMMUTABLEist das Schreiben von Funktionen, die als Teil von Indexausdrücken verwendet werden sollen.

Craig Ringer
quelle
1
"Sie können nicht auf Tabellen zugreifen." Fairerweise können und tun sie es. Ich denke, eine allgemeinere Regel ist, dass die Tabellen ohne Neustart der Datenbank nicht sinnvoll mutieren sollen.
Evan Carroll
Wenn STABLE den Tabellenzugriff zulässt, gibt es Optimierungen über / über VOLATILE ...?
Brooks
Ich erinnere mich nicht, dass ich Dokumente / Code überprüfen müsste.
Craig Ringer
4

Für STABLE ist der fett gedruckte Teil "Ergebnis kann sich über SQL-Anweisungen hinweg ändern".

IMMUTABLE Dinge sollen sich nie ändern. Selbst wenn Sie starten Sie Ihren Datenbankserver läuft yum update(aber natürlich kann es Fehler sein!), Ändern Sie Ihre Konfiguration (wie datestyle, timezone, default_text_search_config, extra_float_digits, etc.) oder Ihre Server - Hardware vollständig (von der gleichen Architektur wie die alte Hardware ersetzen, so Die Binärdateien sind weiterhin kompatibel.

Die von Ihnen beschriebenen Funktionen klingen wie STABIL, da sie in einer einzelnen SQL-Anweisung ihre Abfragen mit demselben Snapshot wie die äußere Abfrage ausführen und daher alle gleichzeitigen Änderungen, die Sie an diesen anderen Tabellen vorgenommen haben, nicht sichtbar sind. Wenn Ihre Funktionen nun eine neue Verbindung zum Server öffnen und ihre Abfragen innerhalb dieser unabhängigen Verbindung ausführen, würde dies die Funktion flüchtig machen, da sie unterschiedliche Snapshots verwenden würden.

jjanes
quelle
Ich glaube, ich verstehe die Voraussetzungen für IMMUTABLE (nichts kann sich ändern ... zwischen Abfragen, Verbindungen, Neustarts, Zerstörung und Rekonstruktion des Planeten, AUCH WENN die Datenbank geändert wird) und VOLATILE (die Funktion springt außerhalb des Kontexts in wie es genannt wurde). Ist das korrekt? Dann scheint STABLE einfach zu bedeuten, dass die Funktion die Datenbank nicht ändert und nicht außerhalb ihres Kontexts auf die Datenbank zugreift. Die Definition von STABLE scheint viel komplizierter zu sein, als es wirklich sein muss ... Oder lasse ich etwas aus?
Brooks
PostgreSQL hat tatsächlich einige Probleme IMMUTABLEund Kollatierungen. Es vertraut darauf, dass glibc(oder in neueren Seiten iconv) die Kollatierungsdefinitionen nicht ändern. In Wirklichkeit tun sie dies und bieten keine Möglichkeit, solche Änderungen zu erkennen. Es kann zu einer stillen Indexbeschädigung führen :(. Es ist meistens ein Problem beim Replizieren zwischen verschiedenen Betriebssystemversionen usw.
Craig Ringer