1. Documentación en Tahiti -> Masters Book List -> Backup and Recovery User’s Guide -> 7 Using Flashback Database and Restore Points
Documentación en Tahiti -> Masters Book List -> Backup and Recovery User’s Guide -> 18 Performing Flashback and Database Point-in-Time Recovery
Documentación en Tahiti -> Masters Book List -> Advanced Application Developer’s Guide -> 12 Using Oracle Flashback Technology
2. Volvemos a reparasar las tecnologías de Flashback que proporciona Oracle.
3. Flashback Drop nos permite recuperar tablas borradas (DROP TABLE) practicamente de forma inmmediata. Si tenemos activada la papelera de reciclaje (RECYCLEBIN), cuando borramos un objeto no se libera el espacio automática, sino que se actualiza el diccionario de datos indicando que se ha borrado la tabla y el espacio será reutilizado cuando sea necesario. Los primeros objetos que se purgarán serán los primeros que se hayan eliminado.
-- Creamos un tabla para realizar las pruebas CREATE TABLE TEST_EMPLOYEES TABLESPACE USERS AS SELECT * FROM HR.EMPLOYEES; -- Borramos la tabla DROP TABLE TEST_EMPLOYEES; -- Consultamos la papelera de reciclaje para ver el objeto recién borrado -- RECYCLEBIN = USER_RECYCLEBIN (También podríamos usar DBA_RECYCLEBIN) SELECT * FROM RECYCLEBIN; -- Recuperamos la tabla FLASHBACK TABLE TEST_EMPLOYEES TO BEFORE DROP; -- Consultamos la tabla SELECT COUNT(*) FROM TEST_EMPLOYEES;
Cuando recuperamos la tabla, tenemos la opción de recuperarlo con un nombre distinto.
-- Borramos la tabla DROP TABLE TEST_EMPLOYEES; -- Recuperamos la tabla FLASHBACK TABLE TEST_EMPLOYEES TO BEFORE DROP RENAME TO TEST_EMPLOYEES_OLD; -- La renombramos con el nombre original RENAME TEST_EMPLOYEES_OLD TO TEST_EMPLOYEES;
Una problemática que puede surgir es que hayamos borrado varias tablas con el mismo nombre y no sepamos cuál debemos recuperar. El procedimiento es el siguiente.
-- Borramos la tabla anterior DROP TABLE TEST_EMPLOYEES; -- Creamos una segunda tabla con el mismo nombre pero si registros CREATE TABLE TEST_EMPLOYEES TABLESPACE USERS AS SELECT * FROM HR.EMPLOYEES WHERE 1=2; -- Borramos la segunda tabla DROP TABLE TEST_EMPLOYEES; -- Comprobamos el contenido de la RECYCLEBIN y vemos que tenemos dos tablas "TEST_EMPLOYEES" SELECT * FROM RECYCLEBIN WHERE ORIGINAL_NAME='TEST_EMPLOYEES'; -- Podemos consultar datos de las tablas dentro de la propia RECYCLEBIN -- Consultamos el número de filas de las dos SELECT COUNT(*) FROM "BIN$3qdKDJCYSGngQ2QBqMBRgw==$0"; SELECT COUNT(*) FROM "BIN$3qdKDJCdSGngQ2QBqMBRgw==$0"; -- La primera es la que tiene 107 registros luego es la correcta -- Recuperar la primera tabla de la RECYCLEBIN FLASHBACK TABLE "BIN$3qdKDJCYSGngQ2QBqMBRgw==$0" TO BEFORE DROP;
Cuando borramos un objeto, podemos indicar que no se registre en la papelera de reciclaje. También tenemos la opción de purgar toda la papelera de reciclaje entre otras.
-- Borramos la tabla TEST_EMPLOYEES de manera que no se pueda recuperar con Flasback DROP DROP TABLE TEST_EMPLOYEES PURGE; -- Limpiamos la papelera de reciclaje PURGE RECYCLEBIN; -- Purgamos el contenido de la papelera de un tablespace PURGE TABLESPACE USERS; -- Purgamos los objetos de un usuario dentro de un tablesapce PURGE TABLESPACE USERS USER HR; -- Purgamos el contenido de todas las papeleras de reciclaje PURGE DBA_RECYCLEBIN;
Una consideración a tener en cuenta que es que cuando recuperamos un objeto con dependencias de la RECYCLEBIN, los objetos dependientes no recuperan el nombre original, así que tenemos que hacerlo «manualmente».
-- Creamos una tabla de ejemplo CREATE TABLE TEST_EMPLOYEES TABLESPACE USERS AS SELECT * FROM HR.EMPLOYEES; -- Creamos un índice CREATE INDEX IDX_EMPLOYEES ON TEST_EMPLOYEES(EMPLOYEE_ID) TABLESPACE USERS; -- Borramos la tabla DROP TABLE TEST_EMPLOYEES; -- IMPORTANTE! Consultamos los nombres que tienen los objetos borrados SELECT * FROM RECYCLEBIN; -- Recuperamos la tabla FLASHBACK TABLE TEST_EMPLOYEES TO BEFORE DROP; -- Consulta el nombre del índice SELECT INDEX_NAME FROM DBA_INDEXES WHERE TABLE_NAME='TEST_EMPLOYEES'; -- Renombramos el índice ALTER INDEX "BIN$3qdKDJCiSGngQ2QBqMBRgw==$0" RENAME TO "IDX_EMPLOYEES"; -- Limpiamos el entorno DROP TABLE TEST_EMPLOYEES PURGE;
4. Flashback Database es una funcionalidad muy potente para llevar la BD atras en el tiempo. Antes de todo vamos a crear un punto de restauración, que nos permite «etiquetar» un punto en el tiempo para poder llevar la BD al principio de todos los ejercicios.
-- La clausula GUARANTEE indica que se guarden los Flashback Logs más alla de la Retención CREATE RESTORE POINT BEFORE_EXERCISES GUARANTEE FLASHBACK DATABASE; -- Vemos los puntos de restauración de la BD SELECT * FROM V$RESTORE_POINT;
Probamos a borrar todo un esquema y recuperaremos la BD.
-- Borramos el esquema HR DROP USER HR CASCADE; -- Realizamos un FLASHBACK completo de la BD al punto de restauración -- Tenemos que tener la BD en estado MOUNT STARTUP MOUNT FORCE FLASHBACK DATABASE TO RESTORE POINT BEFORE_EXERCISES; -- Abrimos la BD ALTER DATABASE OPEN RESETLOGS;
Hagamos un ejercicio más complicado para ver como podemos ir hacia detrás y hacia delante con FLASHBACK y RECOVER.
-- Creamos un segundo punto de restauración CREATE RESTORE POINT AFTER_EXERCISES GUARANTEE FLASHBACK DATABASE; -- Consultamos los puntos de restauración para obtener los SCN SELECT * FROM V$RESTORE_POINT; -- En mi caso esta es la salida -- SCN NAME -- ---------- ------------------ -- 3124322 BEFORE_EXERCISES -- 3124333 AFTER_EXERCISES -- -- Llevamos la BD al 2º punto (AFTER EXERCISES) STARTUP FORCE MOUNT FLASHBACK DATABASE TO RESTORE POINT AFTER_EXERCISES; -- Abrimos la BD en modo lectura para comprobar si nos interesate este punto ALTER DATABASE OPEN READ ONLY; -- Supongamos que no nos interesa y queremos volver al punto anterior -- Pero esta vez, en vez de usar la etiquita "BEFORE_EXERCISES", usaremos el SCN STARTUP FORCE MOUNT FLASHBACK DATABASE TO SCN 3124322; -- Si decidimos que no queremos ir marcha atrás, podemos hacer un RECOVER RECOVER DATABASE; -- Levantamos la BD (Fijaros que no usamos RESETLOGS) ALTER DATABASE OPEN; -- Borramos los puntos de restauración. DROP RESTORE POINT BEFORE_EXERCISES; DROP RESTORE POINT AFTER_EXERCISES;
No lo haremos pero tenemos estas otras opciones para hacer FLASHBACK.
-- Flashack Database a un tiempo concreto FLASHBACK DATABASE TO TIMESTAMP (TO_TIMESTAMP('2013/06/08 19:14:35','YYYY/MM/DD HH24:MI:SS')); -- Flashback hasta una secuencia (dentro de RMAN) FLASHBACK DATABASE TO SEQUENCE=1;
Si la BD tiene que recuperar muchos bloques y la operación se alarga en el tiempo, podemos monitorizar el progreso con la siguiente consulta (V$SESSION_LONGOPS)
SELECT SOFAR, TOTALWORK, UNITS FROM V$SESSION_LONGOPS WHERE OPNAME='Flashback Database';
5. En ocasiones nos puede interesar hacer marchá atrás de una serie de transacciones sobre una tabla. No es una operación frecuente, pero es interesante saber cómo se puede hacer. Para ello vamos a utilizar las funcionalidades de Flasbach Transaction Query y Flashback Version Query.
-- Creamos una tabla de ejemplo CREATE TABLE TEST_EMPLOYEES TABLESPACE USERS AS SELECT * FROM HR.EMPLOYEES; -- Borramos dos registros de la tabla TEST_EMPLOYEES DELETE FROM TEST_EMPLOYEES WHERE EMPLOYEE_ID=100; COMMIT; DELETE FROM TEST_EMPLOYEES WHERE EMPLOYEE_ID=101; COMMIT; -- Consultamos las transacciones realizados a partir de la vista FLASHBACK_TRANSACTION_QUERY SELECT * FROM FLASHBACK_TRANSACTION_QUERY WHERE TABLE_NAME='TEST_EMPLOYEES'; -- También podemos obtener información de las transacciones realizadas a través de las pseudocolumnas de Version Query -- Obtenemos sólo aquellos cambios que provegan de un DELETE (VERSIONS_OPERATION='D') SELECT VERSIONS_XID, VERSIONS_STARTSCN, VERSIONS_ENDSCN, VERSIONS_OPERATION, EMPLOYEE_ID, FIRST_NAME FROM TEST_EMPLOYEES VERSIONS BETWEEN SCN MINVALUE AND MAXVALUE WHERE VERSIONS_OPERATION='D' ORDER BY 2; -- A través de las Id de las transacciones (XID), podemos hacer marcha atrás de los DELETEs realizados -- Para ello utilizamos el procedimiento TRANSACTION_BACKOUT del paquete DBMS_FLASHBACK EXEC DBMS_FLASHBACK.TRANSACTION_BACKOUT(2, xid_array('01000C004A030000','09001F0020030000')); -- Consultamos que volvemos a tener los registros SELECT EMPLOYEE_ID, FIRST_NAME FROM TEST_EMPLOYEES WHERE EMPLOYEE_ID IN (100,101); -- Limpiamos el entorno DROP TABLE TEST_EMPLOYEES PURGE;