Abfragen in die Vergangenheit: Flashback Query

Sicherlich kennen Sie schon die Flashback-Funktion in einem interaktiven Bericht. Klicken Sie das Menü auf, wählen Sie den Eintrag Flashback aus und geben Sie ein, wieviele Minuten Sie in der Zeit zurück möchten (Abbildung 1).

Flashback-Funktion in einem interaktiven Bericht
Abbildung 1: Flashback-Funktion in einem interaktiven Bericht

Der Bericht zeigt Ihnen dann die Daten so an, wie Sie zu diesem Zeitpunkt waren. Das ist sehr hilfreich, wenn man versehentlich etwas gelöscht hat. Als Endanwender kann man solche Fehler leicht selbst beheben, ohne dass der Datenbankadministrator aktiv werden muss. Die Flashback-Funktionalität gehört zum Standardumfang der Oracle-Datenbank, ist also nicht nur für interaktive Berichte, sondern auch für andere APEX-Komponenten wie Formulare oder "klassische" Berichte möglich. Dazu müssen Sie allerdings etwas tun - was, das erfahren Sie in diesem Tipp.

Hintergrund

Das Flashback Query-Feature der Oracle-Datenbank gibt es bereits seit Oracle9i. Technische Basis sind die Undo-Tablespaces, in denen die Datenbank alte Versionen eines geänderten Datenblocks ablegt. Die Datenbank nutzt diese before images, wenn auf einen Datensatz zugegriffen wird, der gerade geändert wird. Oracle lässt den lesenden Nutzer nicht warten, sondern zeigt anhand der Before Images den Stand der Daten vor der Änderung an. Ein lesender Nutzer blockiert in der Oracle-Datenbank niemals einen schreibenden und umgekehrt.

Nachdem der schreibende Nutzer seine Änderungen mit COMMIT bestätigt hat (und andere Nutzer die neue Version des Datensatzes lesen können) wird das Before Image eigentlich nicht mehr benötigt. Aus Performancegründen wird es jedoch nicht sofort gelöscht, sondern dann überschrieben, wenn der Platz im Undo Tablespace wieder gebraucht wird. Und solange dies noch nicht passiert ist, erlaubt Flashback Query den Zugriff darauf.

Flashback Query nutzen

Flashback Query kann mit einfach mit der AS OF-Klausel in einer SQL-Abfrage genutzt werden.

select * from emp
as of timestamp systimestamp - interval '5' minute

Wenn Sie zu weit in der Zeit zurückgehen, die Before Images also schon überschrieben wurden, erhalten Sie eine Fehlermeldung.

select * from emp as of timestamp systimestamp - interval '2' year
              *
FEHLER in Zeile 1:
ORA-08180: Kein Snapshot gefunden basierend auf angegebener Zeit

Wie weit Sie tatsächlich in der Zeit zurückgehen können, hängt von der Konfiguration des Datenbankservers (hier: von der Größe des Undo-Tablespace) und von der Last auf dem System ab. Auf unter Last stehenden Produktivsystemen sind wohl maximal 5 bis 15 Minuten realistisch - aber diese Zeit kann dem Endanwender in der Praxis völlig reichen.

Flashback Query in Berichten und Diagrammen nutzen

Dank der AS OF-Klausel ist es recht einfach, Flashback Query auch in einem klassischen Bericht oder in einem Diagramm zu nutzen: Erzeugen Sie sich zunächst eine Anwendungsseite mit Bericht und Diagramm auf die Tabelle EMP. Fügen Sie dann eine weitere Region mit Namen Flashback hinzu. Erstellen Sie in dieser neuen Region ein Texteingabefeld namens PX_FLASHBACK_QUERY und eine Schaltfläche zum Absenden - achten Sie darauf, dass die Schaltfläche ein Submit durchführt, die Seite also weiterleitet.

APEX Anwendungsseite (noch ohne Flashback Features)
Abbildung 2: APEX Anwendungsseite (noch ohne Flashback Features)

Abbildung 2 zeigt, wie die Seite aussehen könnte: Links sehen Sie den (klassichen) Bericht auf die Tabelle EMP, rechts das Diagramm und oberhalb die neue Region Flashback mit einem Texteingabefeld und der Schaltfläche.

Navigieren Sie nun zum Bericht: Die noch einfache SQL-Abfrage (Schwarz) wird mit der AS OF-Klausel (rot) versehen:

select * from emp 
as of timestamp (systimestamp - (nvl(:PX_FLASHBACK_TIME, 0) / (24 * 60 )))

Die AS OF-Klausel bezieht sich übrigens auf eine Tabelle. Wenn Sie in Ihrer Abfrage also mehrere Tabellen per JOIN zusammenführen, können Sie für die einzelnen Tabellen unterschiedliche Versionen auswählen: So ist es möglich, bspw. EMP in der aktuellen Version, DEPT in der Version von vor fünf Minuten auszuwählen. Das Diagramm verwendet übrigens einen solchen Join. Damit Sie die AS OF-Klausel nicht zweimal in das SQL schreiben müssen, verwenden Sie eine Unterabfrage wie folgt.

select * from (
  select null, d.dname, sum(e.sal) salsum
  from emp e join dept d on (e.deptno = d.deptno)
  group by d.dname
)
as of timestamp (systimestamp - (nvl(:PX_FLASHBACK_TIME, 0) / (24 * 60)))

Für solch einfache Darstellungen sind Sie damit auch schon fertig. Sie können die Seite nun starten und einige Minuten in die Vergangenheit "navigieren". Zum Testen löschen oder ändern Sie einfach einen Datensatz im SQL Workshop (COMMIT nicht vergessen) und schauen Sie sich dann in der Anwendungsseite den Zeitpunkt davor an.

Die gleiche Vorgehensweise gilt übrigens für Auswahllisten (LOV), "Popup"-LOV, Kalender- oder Baumregionen. Es muss einfach nur die AS OF-Klausel in die SQL-Abfrage eingebaut werden. U.U. empfiehlt es sich, das Element mit der Flashback-Zeit nicht als Seiten-, sondern als Applikationselement einzurichten.

Flashback Query in Formularen nutzen

Hier stellt sich zunächst die Frage, ob das überhaupt sinnvoll ist; denn Flashback Query kann nur für Abfragen angewendet werden; Datenmanipulationen (DML) können nur "in der Gegenwart" stattfinden. Dennoch wäre es interessant, eine alte Version der Daten in ein Formular zu laden, zu bearbeiten und das Ergebnis "in der Gegenwart" abzuspeichern. Gerade dies ist eine für Endanwender interessante Option: Ein versehentlich gelöschter oder falsch geänderter Datensatz kann so einfacher korrogiert werden - man "lädt einfach die alte Version".

Das Prinzip ist das gleiche: Auch hier muss die AS OF-Klausel ins SQL eingebaut werden. Genau deswegen kann Flashback Query allerdings nicht in Formulare, die mit den APEX-Assistenten erstellt wurden, eingebaut werden. Grund ist der APEX-Prozeß Automated Row Fetch (Automatisierte Zeilenverarbeitung), der die Daten ins Formular lädt: Dieser generiert die SQL-Abfrage komplett selbst und es gibt daher keine Möglichkeit, die AS OF-Klausel dort einzubauen.

Das Formular muss demnach "manuell" erstellt werden: Erstellen Sie also, wie im APEX Community-Tipp Formulare manuell erstellen beschrieben, ein Formular für die Tabelle EMP manuell. Verküpfen Sie dann den Bericht mit dem Formular - wenn der Anwender auf die EMPNO klickt, sollen die Daten ins Formular geladen werden (Berichtsattribute - Spaltenattribute "EMPNO" - Link).

Das entscheidende ist, dass Sie das SQL der Prozesse für den Zeilenabruf und die Zeilenverarbeitung selbst kontrollieren können - somit können Sie auch die AS OF-Klausel einbauen.

APEX Formular (mit dem Bericht verknüpft)
Abbildung 3: APEX Formular (mit dem Bericht verknüpft)

Bei der Erstellung des Formulars nach der Beschreibung im Community-Tipp haben Sie einen onLoad-Prozeß namens Formular laden erzeugt - dieser enthält die SQL-Abfrage, die nun mit der AS OF-Klausel (hier rot dargestellt) versehen werden muss.

begin
  if :P2_EMPNO is not null then
    begin
      select ename, job, sal, comm, hiredate, deptno, mgr 
      into :P2_ENAME, :P2_JOB, :P2_SAL, :P2_COMM, :P2_HIREDATE, :P2_DEPTNO, :P2_MGR
      from emp 
      as of timestamp systimestamp - (:PX_FLASHBACK_TIME / (24 * 60 ))
      where empno = :P2_EMPNO;
      htp.p(apex_item.md5_checksum(:P2_ENAME, :P2_JOB, :P2_SAL, :P2_COMM, :P2_HIREDATE, :P2_DEPTNO, :P2_MGR));
    exception
      when NO_DATA_FOUND then
        :P2_EMPNO := null;
      when TOO_MANY_ROWS then
        :P2_EMPNO := null;
    end;
  end if;
end; 

Der onSubmit-Prozeß, der die Formulareingaben speichert, muss nicht geändert werden; Manipulationen finden schließlich "in der Gegenwart" statt. Fügen Sie dem Formular zum Schluß noch eine weitere Schaltfläche hinzu:

  • Name: CREATE (Sie haben dann zwei Schaltflächen "CREATE", das soll so sein)
  • Label: Erneut erstellen
  • Bedingung: PX_FLASHBACK_TIME is not null

Nun können Sie es ausprobieren: Starten Sie die Seite, laden Sie eine der Tabellenzeilen ins Formular und löschen Sie diese. Normalerweise wäre die Zeile nun weg.

Gehen Sie nun einige Minuten zurück und lassen Sie sich den Bericht vor dem Löschen der Zeile anzeigen. Laden Sie den gelöschten Datensatz wieder ins Formular und klicken Sie auf die zuletzt erstellte Schaltfläche Erneut erstellen. Anschließend können Sie die Flashback-Zeit wieder auf Null setzen - Sie haben den Datensatz als Endanwender wiederhergestellt.

Weitere Informationen

Flashback Query ist Teil einer ganzen Reihe von Features, die unter dem Begriff Oracle Flashback-Technologie zusammengefasst sind. Neben der reinen Abfrage zu einem bestimmten Zeitpunkt in der Vergangenheit lassen sich alle Änderungen, die seitdem aufgetreten sind, mit der Flashback Versions Query nachvollziehen. Das Flashback Table-Kommando setzt eine Tabelle auf den Zustand zurück, den sie zum angegebenen Zeitpunkt hatte. Und mit den Flashback Data Archives, die mit Oracle11g eingeführt wurden, können Sie noch wesentlich weiter in der Vergangenheit zurückzugehen, als es mit dem "normalen" Flashback Query möglich wäre.

Zurück zur Community-Seite