mardi 27 octobre 2009

La technique du FlashBack en 10g

Introduction


En version 9i, oracle a introduit la notion de FlashBack query. En français, la possibilité d’interroger une table à un e époque révolue. Mécanisme bien sympathique pour prévenir les erreurs utilisateurs.

En 10g, ce mécanisme a été profondément perfectionné et permet de nombreuses opérations permettant de revenir en arrière sur des erreurs et ce, sur 3 niveaux :
- au niveau d’une ligne
- au niveau d’une table
- au niveau d’une base de données complète.

Principe de fonctionnement


Le principe est différent selon l’opération de flashback à réaliser.
- Si l’opération se situe au niveau ligne ou table (hors DROP) alors ce sont les informations d’annulation (UNDO) qui seront utilisées. Il est donc capital de bien régler le paramètre UNDO_RETENTION et la taille du tablespace d’annulation pour pouvoir revenir assez loin en arrière. Si le terme d’annulation n’évoque rien pour vous, une petite lecture s’impose ici : les annulations en 9i et 10g.
- Si l’opération concerne un flashback avant DROP d’une table. Alors l’opération utilise le fait qu’une table n’est pas réellement supprimée. Utilisation de la "Corbeille" oracle.
- Si l’opération concerne un flashback de la base de données. Alors l’opération utilise une nouvelle forme de journaux appelés journaux de FlashBack. Ces journaux sont stockés dans la flashback Recovery Area (nouveau en 10g), et dispose de l’extension FLB. Ils sont générés périodiquement et contiennent la liste des blocs modifiés durant cette période. Ils sont généralement moins volumineux que des ARCHIVE Logs. Cela dit, si on désire, réaliser un Flashback au niveau de la base de données. Celle ci doit être en mode ARCHIVELOG. En effet, les journaux de FLASHBACK ne contiennent que les blocs modifiés. Lors d’une opération de FLASHBACK DATABASE, ces blocs seront remis en place à l’instant demandé. Cela dit, il se peut qu’il y ait un décalage entre le temps demandé et le temps d’enregistrement du blocs. Pour se garder de cette différence et donc pour maintenir la cohérence de la base, on aura besoin de jouer les ARCHIVELOG.

Configuration


Niveau Ligne et tables (hors DROP)


Nous venons de voir que pour un flashback sur ligne ou sur table (hors DROP). Le tout se faisait dans le tablespace d’annulations. Il faut donc configurer les paramètres UNDO_RETENTION et la taille du tablespace d’annulations de la sorte.

Plus on désire revenir longtemps en arrière par une telle opération et plus il faudra augmenter le paramètre UNDO_RETENTION et également la taille du tablespace. Il y a donc une décision à prendre sur ce sujet dans le design de la base.

Niveau table après Suppression : DROP


Si on désire réaliser des flashback de table après les avoir supprimées. Il faut activer la "Corbeille" Oracle. Cette opération se fait en activant le paramètre RECYCLEBIN. C’est un paramètre dynamique pouvant être modifié pour la session ou pour le système. Par défaut, il est actif. Si le paramètres est inactif (OFF), il sera impossible d’effectuer un FLASHBACK après suppression sur les tables supprimées.

Ex :

ALTER SYSTEM SET RECYCLEBIN = ON SCOPE=SPFILE;
ALTER SESSION SET RECYCLEBIN = OFF;

Niveau Base de données


Pour pouvoir réaliser un FLASHBACK complet sur la base de données. Il faut :
- Configurer la zone de flash ou Flash Recovery Area
- Configurer le temps de retention pour effectuer une telle opération de Flashback
- Activer le mode FLASHBACK pour la base de données.
- Etre en mode ARCHIVELOG

- Configuration de la Flash Recovery Area. Cette zone de récupération va nous permettre de stocker les journaux de FlashBack. Elle pourra également servir de stockage des ARCHIVE LOGS, des Backup Sets RMAN. Il font donc lui donner une localisation et une taille suffisante pour contenir tous ces objets.

Cette zone se configure avec les paramètres : DB_RECOVERY_FILE_DEST : pour spécifier la localisation de la Flash Recovery Area. On peut lui spécifier une localisation physique ou un groupe de disques ASM. De plus, en environnement RAC (Real Application Cluster), toutes les instances doivent avoir la même déstination.

DB_RECOVERY_FILE_DEST_SIZE : pour spécifier la taille de la Flash Recovery Area.

Par exemple : Si on désire configurer une Flash Recovery Area dans /u02/orcl/flash de 5 GigaOctets :

ALTER SYSTEM SET DB_RECOVERY_FILE_DEST = '/u02/orcl/flash' SCOPE=SPFILE;
ALTER SYSTEM SET DB_RECOVERY_FILE_DEST_SIZE = 5G SCOPE=SPFILE;

Puis redémarrer l’instance.

- Configuration du temps de rétention des informations de logs FlashBack.

Nous avons vu, plus haut, que le flashback database était rendu possible par des journaux spécifiques stockés dans la Flash Recovery Area. Ces fichiers vont contenir les informations d’une certaine période. Cette période est définie par le paramètre : DB_FLASHBACK_RETENTION_TARGET. Ce paramètre correpond au temps (en minutes) de conservation de ces journaux.

Si, par exemple, ce temps est réglé à 1440 (par défaut), alors il sera possible de revenir en arrière, au plus loin, une journée (24*60) avant l’opération.

- Activation du mode FLASHBACK

L’activation du mode FLASHBACK se réalise lorsque la base est en mode MOUNT. Je vous conseille donc de régler les paramètres précédents dans le SPFILE puis de redémarrer l’instance en lui donnant le bon mode de fonctionnement :

SHUTDOWN IMMEDIATE;
...
STARTUP MOUNT;
ALTER DATABASE FLASHBACK ON;
ALTER DATABASE OPEN;

La vérification se fera dans la vue V$DATABASE (d’ou l’intérêt de configurer toutes les instances RAC à l’identique : c’est la base de données qui est activée dans le mode FLASHBACK) :

SQL> select name,flashback_on from v$database;


NAME      FLASHBACK_ON
--------- ------------------
ORCL      YES

Retour en Arrière !


Niveau Ligne


La commande de fonctionnement est la suivante :

SELECT colonne1[,colonne2,...,colonneN]
FROM table AS OF {TIMESTAMP | SCN} expression;

Mais plutôt que de grands discours, je vous propose un exemple :

SQL>  connect / as sysdba
Connected.
SQL> grant execute on dbms_flashback to hr;


Grant succeeded.

SQL> connect hr/hr
Connected.

SQL> select * from regions where region_id=4;

REGION_ID REGION_NAME
---------- -------------------------
4 Middle East and Africa

SQL> select to_char(SYSDATE,'DD/MM/YYYY HH24:MI:SS') as MAINTENANT,
2         dbms_flashback.get_system_change_number as SCN_COURANT
3  from dual;

MAINTENANT          SCN_COURANT
------------------- -----------
26/11/2005 16:11:39      700821

SQL> -- On va prendre un café et on revient ;)
SQL> select to_char(SYSDATE,'DD/MM/YYYY HH24:MI:SS') as MAINTENANT,
2         dbms_flashback.get_system_change_number as SCN_COURANT
3  from dual;

MAINTENANT          SCN_COURANT
------------------- -----------
26/11/2005 16:13:59      701157

SQL> update regions set region_name='Groenland' where region_id=4;

1 row updated.

SQL> commit;

Commit complete.

SQL> -- On va reprendre un café
SQL> -- histoire de passer un peu de temps ;)
SQL> select to_char(SYSDATE,'DD/MM/YYYY HH24:MI:SS') as MAINTENANT,
2         dbms_flashback.get_system_change_number as SCN_COURANT
3  from dual;

MAINTENANT          SCN_COURANT
------------------- -----------
26/11/2005 16:18:48      702192

SQL> -- Et maintenant, on revient en arriere.
SQL> -- En jouant avec la date ...
SQL> select *
2  from regions AS OF TIMESTAMP SYSTIMESTAMP - INTERVAL '10' MINUTE
3  where region_id=4;

REGION_ID REGION_NAME
---------- -------------------------
4 Middle East and Africa

SQL> ... ou avec le SCN
SQL> select *
2  from regions AS OF SCN 700821
3  where region_id=4;

REGION_ID REGION_NAME
---------- -------------------------
4 Middle East and Africa

SQL> Pour remettre le tout en ordre, il suffit de réaliser un update
SQL> SQL> update regions set region_name=
2  (select region_name
3   from regions AS OF SCN 700821
4   where region_id=4)
5  where region_id=4;

1 row updated.

SQL> commit;

Commit complete.

SQL> select * from regions where region_id=4;

REGION_ID REGION_NAME
---------- -------------------------
4 Middle East and Africa

Niveau Table


Données supprimées Pour revenir en arrière lorsqu’on a tout supprimé dans une table (hors structure). On réalise la séquence suivante :

FLASHBACK TABLE Table
AS OF {TIMESTAMP | SCN} expression
[ENABLE TRIGGERS];

Pour réaliser une telle opération il faut :
- Avoir le droit FLASHBACK sur la table
- Disposer des autorisation SELECT, INSERT et ALTER sur la table à restaurer
- Activer le déplacement de lignes sur la table (ALTER TABLE table ENABLE ROW MOVEMENT) sous peine de ORA-08189.

SQL> select count(*) from regions_bis;


COUNT(*)
----------
4

SQL> delete from regions_bis;

4 rows deleted.

SQL> commit;

Commit complete.

SQL> -- Oups ....
SQL> -- 10 minutes plus tard, j'envisage le FLASHBACK;
SQL> ALTER TABLE regions_bis ENABLE ROW MOVEMENT;

Table altered.

SQL> FLASHBACK TABLE regions_bis TO TIMESTAMP SYSTIMESTAMP - INTERVAL '10' MINUTE;

Flashback complete.

SQL> select count(*) from regions_bis;

COUNT(*)
----------
4

Table supprimée Nous avons vu plus haut, qu’en 10g, Oracle s’est doté d’une "Corbeille" ou "Recycle bin". Cette corbeille va nous permettre, si elle est activée, de récupérer une table ayant subit un DROP.

En terme de fonctionnement, tout objet supprimé, est marqué comme supprimé et placé dans la vue DBA_RECYCLEBIN (au niveau DBA) ; le niveau USER sera représenté par la vue USER_RECYCLEBIN. Une fois ces objets marqués comme supprimés. Ils pourront être récupérés. Cela dit, si le système demande des extensions suite à un manque d’espace dans le tablespace. Les extensions des segments placés dans la corbeille seront recyclés dans de nouvelles extensions.

La encore, je vais agrémenter d’un exemple, qui sera plus parlant que des longs discours.

SQL> conn / as sysdba
Connected.
SQL> show parameter recyclebin


NAME                  TYPE        VALUE
--------------------- ----------- ------
recyclebin            string      on

SQL> conn hr/hr
Connected.
Name                    Null?    Type
----------------------- -------- -------------
OBJECT_NAME             NOT NULL VARCHAR2(30)
ORIGINAL_NAME                    VARCHAR2(32)
OPERATION                        VARCHAR2(9)
TYPE                             VARCHAR2(25)
TS_NAME                          VARCHAR2(30)
CREATETIME                       VARCHAR2(19)
DROPTIME                         VARCHAR2(19)
DROPSCN                          NUMBER
PARTITION_NAME                   VARCHAR2(32)
CAN_UNDROP                       VARCHAR2(3)
CAN_PURGE                        VARCHAR2(3)
RELATED                          NOT NULL NUMBER
BASE_OBJECT                      NOT NULL NUMBER
PURGE_OBJECT                     NOT NULL NUMBER
SPACE                            NUMBER

SQL> select object_name,original_name,type from user_recyclebin;

no rows selected

SQL> drop table regions_bis;

Table dropped.

SQL> select object_name,original_name,type from user_recyclebin;

OBJECT_NAME                    ORIGINAL_NAME   TYPE
------------------------------ --------------- -----------------
BIN$M958iDMLSwiRr1va7ePQ0A==$0 REGIONS_BIS     TABLE

SQL> show recyclebin;
ORIGINAL NAME    RECYCLEBIN NAME                OBJECT TYPE  DROP TIME
---------------- ------------------------------ ------------ -------------------
REGIONS_BIS      BIN$M958iDMLSwiRr1va7ePQ0A==$0 TABLE        2005-11-27:16:11:53

SQL> desc regions_bis;
ERROR:
ORA-04043: object regions_bis does not exist

SQL> -- maintenant on restaure la table avant le DROP dans son nom original
SQL> FLASHBACK TABLE regions_bis TO BEFORE DROP;

Flashback complete.
SQL> desc regions_bis;
Name                  Null?    Type
--------------------- -------- -------------
REGION_ID             NOT NULL NUMBER
REGION_NAME                    VARCHAR2(25)

SQL> select object_name,original_name,type from user_recyclebin;

no rows selected

SQL> drop table regions_bis;

Table dropped.

SQL> -- On restaure la table et on en profite pour la renommer
SQL> FLASHBACK TABLE regions_bis TO BEFORE DROP RENAME TO regions_bis_repetita;

Flashback complete.

SQL> desc regions_bis;
ERROR:
ORA-04043: object regions_bis does not exist

SQL> desc regions_bis_repetita;
Name                  Null?    Type
--------------------- -------- ---------------------------
REGION_ID             NOT NULL NUMBER
REGION_NAME                    VARCHAR2(25)

SQL> -- Maintenant on supprime définitivement la table regions_bis_repetita:
SQL> drop table regions_bis_repetita;

Table dropped.

SQL> show recyclebin;
ORIGINAL NAME    RECYCLEBIN NAME                OBJECT TYPE  DROP TIME
---------------- ------------------------------ ------------ -------------------
REGIONS_BIS_REPE BIN$LwfJR8+sTp2bksjHK5b3AQ==$0 TABLE        2005-11-27:16:21:30
TITA
SQL> purge recyclebin;

Recyclebin purged.

SQL> show recycle_bin;
SQL>

NB : Si on désire purger un seul objet de la Corbeille, on peut utiliser la commande :

PURGE {TABLE|INDEX} nom_de_l_objet;

Niveau base de données


Tout d’abord, il nous faut savoir vers quelle point maximum il nous est possible de revenir en arrière. Pour cela, la vue système V$FLASHBACK_DATABASE_LOG nous permettra d’obtenir la réponse :

SQL> select to_char(oldest_flashback_time,'DD/MM/YYYY HH24:MI')
2  from v$flashback_database_log
3  /


TO_CHAR(OLDEST_F
----------------
23/11/2005 22:28

Ensuite, on peut établir un FLASHBACK de la base de données. Le FLASHBACK d’une base de données implique deux points :
- la base de donneés doit être dans l’état MONTEE en ARCHIVELOG
- l’opération nécessite une remise à zéro des journaux de transaction (option OPEN RESETLOGS) et donc une nouvelle incarnation de la base.

Pour revenir une heure en arrière :

SQL> SHUTDOWN IMMEDIATE;
SQL> STARTUP MOUNT;
SQL> FLASHBACK DATABASE TO TIMESTAMP SYSDATE-1/24
SQL> ALTER DATABASE OPEN RESETLOGS;

Aucun commentaire:

Enregistrer un commentaire