Oracle: commit - wann sichtbar?

Bei uns ist gerade eine Frage zu Transaktionen aufgekommen, folgendes Szenario:

Eine Session schriebt per INSERT einen neuen Eintrag in eine Tabelle und schliesst die Transaktion mittels commit ab. Unmittelbar nach dem Commit - bestenfalls einige ms später - führt eine andere Session ein normales SELECT aus. Sporadisch kommt es vor, dass dem SELECT die zuvor committeten Transaktionen entgehen, d.h. sie (noch) nicht sieht.

Nun kommt die Frage nach der Bedeutung von Commit auf. Aus der Oracle Dokumentation geht hervor, dass nach einem erfolgreichen Commit die Daten festgeschrieben sind.
Weiterhin ist definiert, dass konkurriende Sessions stets einen konstistenten Stand der Datenbank sehen, also entweder den vor oder den nach der Transaktion.

Gibt es irgendwelche Dokumente oder Standards die eine Aussage darüber treffen, wann Änderungen für andere Sessions sichtbar werden? Garantiert der Commit also, dass ab sofort alle anderen Session meine Änderungen sehen? Oder muss ich davon ausgehen, dass meine Änderungen trotz commit erst zeitlich verzögert für andere Sessions sichtbar werden?

Mir geht es dabei um die grundsätzliche Frage, muss ich Vorkehrungen für diesen Fall treffen oder kann ich mich auf die Datenbank verlassen.

Gruß Markus

Hallo Markus!

Im Grunde muss ich gestehen: Ich verstehe deine Frage nicht ganz… Das Absetzen eines COMMITs teilt der Datenbank mit, dass die Transaktion abgeschlossen ist und dass die in der Transaktion vorgenommenen Änderungen auch tatsächlich durchgeführt werden sollen. Dass die Datenbank das auch tatsächlich tun muss - wofür zumindest irgendwo irgendein Flag gesetzt werden muss, oder wie auch immer das spezielle RDBMS das handhabt (in Wahrheit steckt da natürlich schon einiges mehr dahinter) - ist ja wohl sonnenklar. Daher kann auch die Änderung nicht in Nullzeit sichtbar sein, weil jede Änderung eben Zeit braucht; wenn du spitzfindig sein willst: Unter einem Maschinentakt geht da definitiv gar nichts - realistisch sind aber wohl eher einige Millisekunden (was ja auch deinen Beobachtungen entspricht). Wenn diese Änderungen aber durchgeführt sind, dann sind die geänderten Daten natürlich für alle Sessions sichtbar, davor eben nicht. Ich verstehe immer noch nicht, wo da jetzt dein Problem liegt… ???

Gruß
Martin

Hallo Markus!

Im Grunde muss ich gestehen: Ich verstehe deine Frage nicht
ganz… Das Absetzen eines COMMITs teilt der Datenbank mit,
dass die Transaktion abgeschlossen ist und dass die in der
Transaktion vorgenommenen Änderungen auch tatsächlich
durchgeführt werden sollen. Dass die Datenbank das auch
tatsächlich tun muss - wofür zumindest irgendwo irgendein Flag
gesetzt werden muss, oder wie auch immer das spezielle RDBMS
das handhabt (in Wahrheit steckt da natürlich schon einiges
mehr dahinter) - ist ja wohl sonnenklar. Daher kann auch die
Änderung nicht in Nullzeit sichtbar sein, weil jede Änderung
eben Zeit braucht; wenn du spitzfindig sein willst: Unter
einem Maschinentakt geht da definitiv gar nichts - realistisch
sind aber wohl eher einige Millisekunden (was ja auch deinen
Beobachtungen entspricht). Wenn diese Änderungen aber
durchgeführt sind, dann sind die geänderten Daten natürlich
für alle Sessions sichtbar, davor eben nicht. Ich verstehe
immer noch nicht, wo da jetzt dein Problem liegt… ???

Vielleicht muß ich mich präziser ausdrücken. Vereinfach ausgedrückt ist das Commit ein Funktionsaufruf auf die Datenbank. Ich rufe also die Funktion commit() auf und warte bis der Aufruf zurückkehrt. Mit der Rückkehr vom Funktionsaufruf ist der „commit“ für mich abgeschlossen.
Nachdem der Funktionsaufruf beendet ist, sind laut Definition alle Änderungen festgeschrieben und meine Applikationen muss sich keine Gedanken mehr zu deren Persistenz machen.

Heisst festgeschrieben, dass mit der Rückkehr vom commit() garantiert ist, dass eine andere Session diese Änderungen sehen muss?

Folgenden Abschnitt habe ich zum Thema Commit gefunden:
Bereits in zentralisierten DBS kommt der Commit-Behandlung durch das DBS eine entscheidende Rolle hinsichtlich der Atomarität und Dauerhaftigkeit von Transaktionen zu. Nachdem der Benutzer (bzw. das Anwendungsprogramm) mit der EOT-Anweisung das Transaktionsende signalisiert, werden DBVS-seitig zwei Phasen durchlaufen. Zunächst werden sämtliche Datenbankänderungen sowie ein sogenannter Commit-Satz auf die Log-Datei geschrieben (Phase 1)[24]. Wurde diese Phase erfolgreich abgeschlossen, d.h., der Commit-Satz wurde auf die Log-Datei geschrieben, ist das erfolgreiche Ende der Transaktion garantiert („Alles“-Fall). Durch das Schreiben der Log-Daten ist die Wiederholbarkeit der Transaktion auch nach einem Rechnerausfall gewährleistet. In Phase 2 der Commit-Behandlung werden dann erst die Änderungen der erfolgreich beendeten Transaktion anderen Transaktionen sichtbar gemacht, z.B. durch Freigabe der Sperren. Transaktionen, die vor Abschluß der ersten Commit-Phase (z.B. durch einen Rechnerausfall) unterbrochen wurden, werden zurückgesetzt („Nichts“-Fall).

Frage: Kehrt der Aufruf von Commit() nach der 1. Phase zurück oder erst nach der 2. Phase?

Gruß Markus

Hallo Markus!

Mit der Rückkehr vom
Funktionsaufruf ist der „commit“ für mich abgeschlossen.
Nachdem der Funktionsaufruf beendet ist, sind laut Definition
alle Änderungen festgeschrieben und meine Applikationen muss
sich keine Gedanken mehr zu deren Persistenz machen.

Das ist an und für sich so richtig. Ich würde allerdings nicht davon ausgehen, dass das Absetzen eines Commits eine synchrone Funktion ist. Unter Oracle kümmern sich einige Prozesse um die Eintragungen von Änderungen in die Datenbank. Ich persönlich sehe keine Notwendigkeit mit der Rückkehr vom Commit auf den Abschluss der Eintragungen durch diese Prozesse zu warten, ausser vielleicht im Fall, wo deine Applikation zeitgleich mehrere Sessions verwendet, wobei die zweite Session die Daten, die die erste Session einträgt „sofort“ anschliessend wieder auslesen will - deshalb auch mein fehlendes Verständnis für deine Frage. Um es auf Steirisch zu sagen: Is es - logisch gesehen - net Blunz’n (= egal), ab wann andere Sessions die Änderungen auch tatsächlich sehen, solange immer ein konsistenter Zustand zurückgeliefert wurde? Mir ist schon klar, dass man von einer performanten DB erwartet, dass es schnell geht, aber ob das jetzt 0,2ms oder 100ms sind - was ändert das an der Logik einer Applikation?

Frage: Kehrt der Aufruf von Commit() nach der 1. Phase zurück
oder erst nach der 2. Phase?

Ich weiss es ehrlich gesagt nicht, würde aber mal raten: so früh wie sinnvoll möglich. Ist aber sicher ein Fall für Metalink. Wobei mir immer noch nicht klar ist, warum das für dich interessant ist…

Gruß
Martin

Das ist an und für sich so richtig. Ich würde allerdings nicht
davon ausgehen, dass das Absetzen eines Commits eine synchrone
Funktion ist. Unter Oracle kümmern sich einige Prozesse um die
Eintragungen von Änderungen in die Datenbank. Ich persönlich
sehe keine Notwendigkeit mit der Rückkehr vom Commit auf den
Abschluss der Eintragungen durch diese Prozesse zu warten,
ausser vielleicht im Fall, wo deine Applikation zeitgleich
mehrere Sessions verwendet, wobei die zweite Session die
Daten, die die erste Session einträgt „sofort“ anschliessend
wieder auslesen will - deshalb auch mein fehlendes Verständnis
für deine Frage. Um es auf Steirisch zu sagen: Is es - logisch
gesehen - net Blunz’n (= egal), ab wann andere Sessions die
Änderungen auch tatsächlich sehen, solange immer ein
konsistenter Zustand zurückgeliefert wurde? Mir ist schon
klar, dass man von einer performanten DB erwartet, dass es
schnell geht, aber ob das jetzt 0,2ms oder 100ms sind - was
ändert das an der Logik einer Applikation?

Nunja, eine Prozess schreibt die Änderung weg und signalisiert das einem weiteren Prozess. Dieser will auf das Datum zugreifen und findet es nicht vor.
Ob es sich hier um ms, Sekunden oder gar Minuten handelt spielt im Prinzip keine Rolle, in jedem Fall muss diese Situation von der Applikation erkannt werden können und bedarf einer gesonderten Behandlung.

Frage: Kehrt der Aufruf von Commit() nach der 1. Phase zurück
oder erst nach der 2. Phase?

Ich weiss es ehrlich gesagt nicht, würde aber mal raten: so
früh wie sinnvoll möglich. Ist aber sicher ein Fall für
Metalink. Wobei mir immer noch nicht klar ist, warum das für
dich interessant ist…

O.g. Situation tritt bei uns auf. Ein Verarbeitungsprozess signalisiert einem Protokollierungsprozess über die Fertigstellung einer Aufgabe, dieser findet aber das Datum nicht und meldet einen Fehler zurück. Die Zeitspanne zwischen den Abfragen liegt im Bereich >150ms, offensichtlich ist sie aber noch zu kurz.

Möglicherweise liegt es aber nur am SELECT, das wird nämlich ohne Transaktion ausgeführt, d.h. es liest einen konsistenten Zustand lässt aber laufende Transaktionen ausser acht. Meine mal gelesen zu haben, dass Transaktionen eine Reihenfolge haben und jede vorab abgeschlossene Transaktion sehen müssen. Wenn das stimmt, könnte ein SELECT FOR UPDATE für Abhilfe sorgen.
Ich werde mir das morgen noch einmal in Ruhe ansehen.

Gruß Markus

Hi!

Um es auf Steirisch zu sagen: Is es net Blunz’n

Voi fia di Wiascht - um es auf oberösterreichisch zu sagen :wink:

Dieser will auf das Datum
zugreifen und findet es nicht vor.

Ganz banal: Kann es sein, daß dieser Prozess die Daten nicht neu liest, sondern jene verwendet, die er gelesen hat? Daß er sich nur die Daten aus dem Cache holt?

Wie wird auf die Datenzugegriffen? (PL/)SQL? Forms? Reports? Irgendwas anderes?

(In Forms wird man höflich mit einen „Record has been updated by another user. Execute the query to see the changes“ oder so ähnlich aufmerksam gemacht)

Wenn das stimmt, könnte ein SELECT FOR UPDATE für Abhilfe
sorgen.

siehe „Ganz Banal“ …

Grüße,
Tomh

Dieser will auf das Datum
zugreifen und findet es nicht vor.

Ganz banal: Kann es sein, daß dieser Prozess die Daten nicht
neu liest, sondern jene verwendet, die er gelesen hat? Daß er
sich nur die Daten aus dem Cache holt?

Nein, das ist ausgeschlossen. Ein Prozess schreibt und ein anderer liest, jeweils auf einer eigenen Session. Wenn es einen Cache gibt, dann liegt dieser bestenfalls auf dem Oracle Server. Für mich ist das transparent.
Aber es geht hier ja auch nicht um irgendwelche Programmfehler, sondern um die Frage: kann/darf so etwas auftreten?

Wie wird auf die Datenzugegriffen? (PL/)SQL? Forms? Reports?
Irgendwas anderes?

Von einer C++ Applikation unter Verwendung des Oracle OCI.

Gruß Markus