# [Oracle] Tutorial zu Flashback



## Exceptionfault (15. Februar 2006)

Hallo,

seit langem komme ich nun endlich wieder dazu ein kleines Tutorial fürs Forum zu verfassen. Wer schonmal einen Beitrag von mir gelesen hat kann sich auch denken was diesmal das Thema sein wird, ;-) Oracle !

Thema soll ein neues, und in meinen Augen geniales Feature, der neuen Oracle Releases 10g sein, das Flashback. Ganz grob zur Einführung könnte man es mit dem Recyclebin oder Papierkorb unter Windows vergleichen. Flashback ermöglicht es tatsächlich mit geringem Aufwand gelöschte Daten wieder herzustellen. Zwar nicht unbegrenzt in die Vergangenheit (es ist eine Frage desSpeicherplatzes...) aber dafür kann es noch viele viele tolle andere Sachen.

Es folgen ein paar kleine Anwendungsbeispiele für Flashback, doch zunächst die technischen Vorbereitungen der Datenbank:

Voraussetzung ist, dass die Datenbank in Archivelog Modus läuft, was bei Produktiven Datenbanken sowieso die Regel sein sollte!
Zweitens muss eine sog. flash_recovery_area definiert werden (INIT.ORA Parameter). Wo die liegt und wieviel Platz dafür reserviert wird kann man durch folgenden Befehl herausfinden:

```
SQL> sho parameter db_recovery

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_recovery_file_dest                string      /u01/flash_recovery_area
db_recovery_file_dest_size           big integer 2G
```
Meine liegt also unter "/u01/flash_recovery_area" (Linux) und darf 2GB groß werden.

Dann müssen wir das Flashback natürlich auch anschalten. Das geht leider nur durch einen Neustart der Datenbank:

```
SQL> shutdown immediate;
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount
ORACLE instance started.

Total System Global Area  201326592 bytes
Fixed Size                  1218508 bytes
Variable Size              67110964 bytes
Database Buffers          130023424 bytes
Redo Buffers                2973696 bytes
Database mounted.

SQL> alter database archivelog;
Database altered.
SQL> alter database flashback on;
Database altered.
SQL> alter database open;
Database altered.
```

Hats funktioniert ?

```
SQL> select FLASHBACK_ON from v$database;
FLASHBACK_ON
------------------
YES
```

Wunderbar. Nun die Vorbereitungen für meine Beispiele... ich brauche eine Benutzer und eine kleine Tabelle:

```
SQL> create user flash identified by back;
User created.
SQL> grant dba to flash;
Grant succeeded.
SQL> conn flash/back
Connected.
SQL> alter session set nls_date_format = 'DD.MM.YYYY HH24:MI:SS';
Session altered.
SQL> create table test (
  2   field1   NUMBER(5) NOT NULL,
  3   field2  VARCHAR2(10) NOT NULL,
  4   field3  DATE NOT NULL
  5  );
Table created.
```

Beim einfügen der Datensätze lasse ich mir etwas Zeit und Committe auch zwischendurch. Nehmen wir an es wären Benutzer die mit dem System gearbeitet haben und Schritt für Schritt Daten erfasst haben.


```
SQL> insert into test values ( 1, 'Hello ', SYSDATE );
1 row created.
SQL> commit;
Commit complete.
SQL> insert into test values ( 2,'World', SYSDATE );
1 row created.
SQL> commit;
Commit complete.
SQL> insert into test values(3,' ',SYSDATE );
1 row created.
SQL> commit;
Commit complete.

SQL> select * from test;
    FIELD1 FIELD2     FIELD3
---------- ---------- -------------------
         1 Hello      15.02.2006 22:55:21
         2 World      15.02.2006 22:56:12
         3         15.02.2006 22:56:29
```
So, nun wird aber im System auch weiter gearbeitet, vielleicht ein paar Daten korrigiert:

```
SQL> update test set field2 = 'User', field3 = SYSDATE where field1 = 2;
SQL> select * from test;

    FIELD1 FIELD2     FIELD3
---------- ---------- -------------------
         1 Hello      15.02.2006 22:55:21
         2 User       15.02.2006 22:58:32
         3         15.02.2006 22:56:29
```
Und natürlich arbeiten auf unserer Applikation auch Azubis ;-)

```
SQL> DELETE FROM TEST;
3 rows deleted.
SQL> commit;
Commit complete.

SQL> select * from test;
no rows selected
```
Oha! Was nun  Ein Backup wieder einspielen dauert viel zu lange. Die Daten wieder eingeben? Die Archive Logs nach den Statements durchsuchen?
Nein, natürlich nicht, sondern Flashback!
Unsere Datenbank hat sich während der ganzen Arbeitszeit unmerklich ein paar Informationen in die Flashback Area geschrieben und die holen iwr uns jetzt wieder zurück. Oracle hat das SELECT Statement um Flashback Optionen erweitert. Schauen wir doch also mal, wie die Tabelle vor wenigen Minuten noch aussah:

```
SQL> select * from test as of timestamp to_date('15.02.2006 22:59:00', 'dd.mm.yyyy hh24:mi:ss');

    FIELD1 FIELD2     FIELD3
---------- ---------- -------------------
         1 Hello      15.02.2006 22:55:21
         2 User       15.02.2006 22:58:32
         3         15.02.2006 22:56:29

SQL> select * from test as of timestamp to_date('15.02.2006 22:58:00', 'dd.mm.yyyy hh24:mi:ss');

    FIELD1 FIELD2     FIELD3
---------- ---------- -------------------
         1 Hello      15.02.2006 22:55:21
         2 World      15.02.2006 22:56:12
         3         15.02.2006 22:56:29
```
Wie man sieht kann ich sowohl den Stand vor dem DELETE als auch vor dem Update ermitteln. Unsere Tabelle ist dabei immernoch leer! Ich mache quasi ein Select in die Vergangenheit. Das geht sogar noch weiter zurück als noch Daten erfasst wurden:

```
SQL> select * from test as of timestamp to_date('15.02.2006 22:55:40', 'dd.mm.yyyy hh24:mi:ss');

    FIELD1 FIELD2     FIELD3
---------- ---------- -------------------
         1 Hello      15.02.2006 22:55:21
```
Gut, jetzt wollen wir aber auch den Schade wieder reparieren. Hierfür müssen wir eine Option der Tabelle ändern, das sog. "row movement". Es dürfte dem normalen User kein Unterschied auffallen ob der Parameter gesetzt ist oder nicht, er entscheidet lediglich über das interne Speicherverhalten der Datensätze.

```
SQL> alter table test enable row movement;
Table altered.
```
Und nun stellen wir die Tabelle wieder her!

```
SQL> flashback table test to timestamp to_date('15.02.2006 22:58:00', 'dd.mm.yyyy hh24:mi:ss');
Flashback complete.
SQL> select * from test;

    FIELD1 FIELD2     FIELD3
---------- ---------- -------------------
         1 Hello      15.02.2006 22:55:21
         2 World      15.02.2006 22:56:12
         3         15.02.2006 22:56:29
```

Cool, oder ?
Aber das geht noch weiter! Setzen wir mal alle Sätze auf das gleiche Datum, das machts etwas leichter zu sehen.

```
SQL> update test set field3 = sysdate;

3 rows updated.

SQL> commit;

Commit complete.

SQL> select * from test;

    FIELD1 FIELD2     FIELD3
---------- ---------- -------------------
         1 Hello      15.02.2006 23:29:00
         2 World      15.02.2006 23:29:00
         3         15.02.2006 23:29:00
```
Jetzt fügen wir einen neuen Satz hinzu und löschen einen anderen raus.

```
SQL> delete from test where field1 = 2;
1 row deleted.
SQL> commit;
Commit complete.
SQL> insert into test values (4, 'Hinzu', SYSDATE);
1 row created.
SQL> commit;
Commit complete.
SQL> select * from test;

    FIELD1 FIELD2     FIELD3
---------- ---------- -------------------
         1 Hello      15.02.2006 23:29:00
         3         15.02.2006 23:29:00
         4 Hinzu      15.02.2006 23:30:44
```

Wie wärs denn jetzt mit einer Liste  der Änderungen ? ;-)

```
SELECT * 
FROM   (
         (  SELECT * FROM TEST
	        UNION
            SELECT * FROM TEST AS OF TIMESTAMP TO_DATE('15.02.2006 23:30:00', 'DD.MM.YYYY HH24:MI:SS')
         )
         MINUS 
         (
            SELECT * FROM TEST
            INTERSECT
            SELECT * FROM TEST AS OF TIMESTAMP TO_DATE('15.02.2006 23:30:00', 'DD.MM.YYYY HH24:MI:SS')
         )
      );

   FIELD1 FIELD2     FIELD3
---------- ---------- -------------------
         2 World      15.02.2006 23:29:00
         4 Hinzu      15.02.2006 23:30:44
```

Nunja, das war wie immer nur ein kleiner Teil der Möglichkeiten. Oracle hat das ganze Spiel natürlich wieder "übertrieben" und ermöglicht nicht nur ein Flashback Table sondern gleich ein Flashback Database *g*.
Das wirklich einzige Problem an der Sache ist: Man darf sich nie drauf verlassen wie lange etwas vorgehalten wird. Wie gesagt liegt das an der Größe der Area und an der auftretenden Last. Je mehr gearbeitet wird, dest mehr Daten fallen an und desto schneller sind die 2GB ( bei mir) voll und alte Sachen fliegen raus.


----------

