martes, marzo 21, 2006

Uso de logminer.


En alguna ocasión he necesitado recuperar una transacción validada con COMMIT, pero no deseada o errónea. Pongo un ejemplo:

- Usuario borra una fila.
- Por accidente.
- No sabe de qué fila se trata, pero 'algo' ha dicho "registro borrado".
- (...borrado y validado).
- Ni idea de qué datos tenía la fila.
- Ni él, ni nadie.
- Desde ese momento, la fila X ha desaparecido sin rastro.

Con variaciones, éste caso es bastante frecuente, y si el usuario que ha borrado el registro es lo suficientemente rápido, existe una posibilidad de recuperar los datos perdidos.

Generalmente, todas las transacciones convencionales procesan la información pasando por las áreas de redo log. En estos archivos está toda la información correspondiente al nuevo cambio. Oracle basa toda su actividad en el buen funcionamiento del registro de redo log y, por tanto, en esta área únicamente almacena los datos físicos elementales para rehacer la operación. Por tanto, no se almacena información sobre los valores anteriores.

Lo cual sí sucede en el área de rollback, y ¡la gestión de rollback también pasa por redolog!.

Oracle dispone de un paquete, el LOG MINER que permite rastrear los redo logs (online y archivados) junto con la información de rollback disponible también en éstos. Una vez ejecutado el paquete que crea el fichero de diccionario de objetos, Oracle es capaz de interpretar esos redologs y mostrar información tan válida como el SQL generado y el SQL inverso para "reparar" la acción.



SQL> connect / as sysdba
Conectado.
SQL> show parameters utl

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
utl_file_dir                         string      c:\oraclefiles

SQL> exec DBMS_LOGMNR_D.BUILD( DICTIONARY_FILENAME =>'dictionary.ora', DICTIONARY_LOCATION => 'c:\oraclefiles');

Procedimiento PL/SQL terminado correctamente.

SQL> select member from v$logfile;

MEMBER
--------------------------------------------------------------------------------
C:\ORACLE\ORADATA\ORCL\REDO04A.LOG
C:\ORACLE\ORADATA\ORCL\REDO04B.LOG
C:\ORACLE\ORADATA\ORCL\REDO05A.LOG
C:\ORACLE\ORADATA\ORCL\REDO05B.LOG
C:\ORACLE\ORADATA\ORCL\REDO06A.LOG
C:\ORACLE\ORADATA\ORCL\REDO06B.LOG

6 filas seleccionadas.

SQL> exec DBMS_LOGMNR.add_logfile('C:\ORACLE\ORADATA\ORCL\REDO04A.LOG');

Procedimiento PL/SQL terminado correctamente.

SQL> exec DBMS_LOGMNR.add_logfile('C:\ORACLE\ORADATA\ORCL\REDO05A.LOG');

Procedimiento PL/SQL terminado correctamente.

SQL> exec DBMS_LOGMNR.add_logfile('C:\ORACLE\ORADATA\ORCL\REDO06A.LOG');

Procedimiento PL/SQL terminado correctamente.

SQL> EXECUTE DBMS_LOGMNR.START_LOGMNR(DICTFILENAME =>'c:\oraclefiles\dictionary.ora');

Procedimiento PL/SQL terminado correctamente.

SQL> set pages 100
SQL> set lines 120
SQL> column sql_redo format a50
SQL> column sql_undo format a50

SQL> select sql_redo, sql_undo from v$logmnr_contents where rownum<10;

SQL_REDO                                           SQL_UNDO
-------------------------------------------------- --------------------------------------------------
insert into "DISCOVERER9I"."EUL5_MV101651"("Import delete from "DISCOVERER9I"."EUL5_MV101651" where "
e SUM","Importe COUNT","Importe MAX","Importe MIN" Importe SUM" = '170,01' and "Importe COUNT" = '1'
,"Importe AVG","Ciudad","Pais","Rango Edad","Sexo" and "Importe MAX" = '170,01' and "Importe MIN" = '
,"Detalle Vuelo") values ('170,01','1','170,01','1 170,01' and "Importe AVG" = '170,01' and "Ciudad"
70,01','170,01','Madeira','Portugal','Mayores de 5 = 'Madeira' and "Pais" = 'Portugal' and "Rango Eda
0 a±os','Mujer','VUELO52149');                     d" = 'Mayores de 50 a±os' and "Sexo" = 'Mujer' and
                                                    "Detalle Vuelo" = 'VUELO52149' and ROWID = 'AAALV
                                                   mAAPAAAAn8AAA';

insert into "DISCOVERER9I"."EUL5_MV101651"("Import delete from "DISCOVERER9I"."EUL5_MV101651" where "
e SUM","Importe COUNT","Importe MAX","Importe MIN" Importe SUM" = '112,95' and "Importe COUNT" = '1'
,"Importe AVG","Ciudad","Pais","Rango Edad","Sexo" and "Importe MAX" = '112,95' and "Importe MIN" = '
,"Detalle Vuelo") values ('112,95','1','112,95','1 112,95' and "Importe AVG" = '112,95' and "Ciudad"
12,95','112,95','Madeira','Portugal','Mayores de 5 = 'Madeira' and "Pais" = 'Portugal' and "Rango Eda
0 a±os','Mujer','VUELO52206');                     d" = 'Mayores de 50 a±os' and "Sexo" = 'Mujer' and
                                                    "Detalle Vuelo" = 'VUELO52206' and ROWID = 'AAALV
                                                   mAAPAAAAn8AAB';

insert into "DISCOVERER9I"."EUL5_MV101651"("Import delete from "DISCOVERER9I"."EUL5_MV101651" where "
e SUM","Importe COUNT","Importe MAX","Importe MIN" Importe SUM" = '123,29' and "Importe COUNT" = '1'
,"Importe AVG","Ciudad","Pais","Rango Edad","Sexo" and "Importe MAX" = '123,29' and "Importe MIN" = '
,"Detalle Vuelo") values ('123,29','1','123,29','1 123,29' and "Importe AVG" = '123,29' and "Ciudad"
23,29','123,29','Madeira','Portugal','Mayores de 5 = 'Madeira' and "Pais" = 'Portugal' and "Rango Eda
0 a±os','Mujer','VUELO52331');                     d" = 'Mayores de 50 a±os' and "Sexo" = 'Mujer' and
                                                    "Detalle Vuelo" = 'VUELO52331' and ROWID = 'AAALV
                                                   mAAPAAAAn8AAC';

insert into "DISCOVERER9I"."EUL5_MV101651"("Import delete from "DISCOVERER9I"."EUL5_MV101651" where "
e SUM","Importe COUNT","Importe MAX","Importe MIN" Importe SUM" = '178,55' and "Importe COUNT" = '1'
,"Importe AVG","Ciudad","Pais","Rango Edad","Sexo" and "Importe MAX" = '178,55' and "Importe MIN" = '
,"Detalle Vuelo") values ('178,55','1','178,55','1 178,55' and "Importe AVG" = '178,55' and "Ciudad"
78,55','178,55','Madeira','Portugal','Mayores de 5 = 'Madeira' and "Pais" = 'Portugal' and "Rango Eda
0 a±os','Mujer','VUELO52419');                     d" = 'Mayores de 50 a±os' and "Sexo" = 'Mujer' and
                                                    "Detalle Vuelo" = 'VUELO52419' and ROWID = 'AAALV
                                                   mAAPAAAAn8AAD';

insert into "DISCOVERER9I"."EUL5_MV101651"("Import delete from "DISCOVERER9I"."EUL5_MV101651" where "
e SUM","Importe COUNT","Importe MAX","Importe MIN" Importe SUM" = '107,36' and "Importe COUNT" = '1'
,"Importe AVG","Ciudad","Pais","Rango Edad","Sexo" and "Importe MAX" = '107,36' and "Importe MIN" = '
,"Detalle Vuelo") values ('107,36','1','107,36','1 107,36' and "Importe AVG" = '107,36' and "Ciudad"
07,36','107,36','Madeira','Portugal','Mayores de 5 = 'Madeira' and "Pais" = 'Portugal' and "Rango Eda
0 a±os','Mujer','VUELO52488');                     d" = 'Mayores de 50 a±os' and "Sexo" = 'Mujer' and
                                                    "Detalle Vuelo" = 'VUELO52488' and ROWID = 'AAALV
                                                   mAAPAAAAn8AAE';

insert into "DISCOVERER9I"."EUL5_MV101651"("Import delete from "DISCOVERER9I"."EUL5_MV101651" where "
e SUM","Importe COUNT","Importe MAX","Importe MIN" Importe SUM" = '120,5' and "Importe COUNT" = '1' a
,"Importe AVG","Ciudad","Pais","Rango Edad","Sexo" nd "Importe MAX" = '120,5' and "Importe MIN" = '12
,"Detalle Vuelo") values ('120,5','1','120,5','120 0,5' and "Importe AVG" = '120,5' and "Ciudad" = 'M
,5','120,5','Madeira','Portugal','Mayores de 50 a± adeira' and "Pais" = 'Portugal' and "Rango Edad" =
os','Mujer','VUELO52561');                          'Mayores de 50 a±os' and "Sexo" = 'Mujer' and "De
                                                   talle Vuelo" = 'VUELO52561' and ROWID = 'AAALVmAAP
                                                   AAAAn8AAF';

insert into "DISCOVERER9I"."EUL5_MV101651"("Import delete from "DISCOVERER9I"."EUL5_MV101651" where "
e SUM","Importe COUNT","Importe MAX","Importe MIN" Importe SUM" = '109,01' and "Importe COUNT" = '1'
,"Importe AVG","Ciudad","Pais","Rango Edad","Sexo" and "Importe MAX" = '109,01' and "Importe MIN" = '
,"Detalle Vuelo") values ('109,01','1','109,01','1 109,01' and "Importe AVG" = '109,01' and "Ciudad"
09,01','109,01','Madeira','Portugal','Mayores de 5 = 'Madeira' and "Pais" = 'Portugal' and "Rango Eda
0 a±os','Mujer','VUELO52690');                     d" = 'Mayores de 50 a±os' and "Sexo" = 'Mujer' and
                                                    "Detalle Vuelo" = 'VUELO52690' and ROWID = 'AAALV
                                                   mAAPAAAAn8AAG';

insert into "DISCOVERER9I"."EUL5_MV101651"("Import delete from "DISCOVERER9I"."EUL5_MV101651" where "
e SUM","Importe COUNT","Importe MAX","Importe MIN" Importe SUM" = '174,91' and "Importe COUNT" = '1'
,"Importe AVG","Ciudad","Pais","Rango Edad","Sexo" and "Importe MAX" = '174,91' and "Importe MIN" = '
,"Detalle Vuelo") values ('174,91','1','174,91','1 174,91' and "Importe AVG" = '174,91' and "Ciudad"
74,91','174,91','Madeira','Portugal','Mayores de 5 = 'Madeira' and "Pais" = 'Portugal' and "Rango Eda
0 a±os','Mujer','VUELO52693');                     d" = 'Mayores de 50 a±os' and "Sexo" = 'Mujer' and
                                                    "Detalle Vuelo" = 'VUELO52693' and ROWID = 'AAALV
                                                   mAAPAAAAn8AAH';

insert into "DISCOVERER9I"."EUL5_MV101651"("Import delete from "DISCOVERER9I"."EUL5_MV101651" where "
e SUM","Importe COUNT","Importe MAX","Importe MIN" Importe SUM" = '131,5' and "Importe COUNT" = '1' a
,"Importe AVG","Ciudad","Pais","Rango Edad","Sexo" nd "Importe MAX" = '131,5' and "Importe MIN" = '13
,"Detalle Vuelo") values ('131,5','1','131,5','131 1,5' and "Importe AVG" = '131,5' and "Ciudad" = 'M
,5','131,5','Madeira','Portugal','Mayores de 50 a± adeira' and "Pais" = 'Portugal' and "Rango Edad" =
os','Mujer','VUELO52951');                          'Mayores de 50 a±os' and "Sexo" = 'Mujer' and "De
                                                   talle Vuelo" = 'VUELO52951' and ROWID = 'AAALVmAAP
                                                   AAAAn8AAI';


9 filas seleccionadas.

7 comentarios:

Anónimo dijo...

Hola que tal muy interesante, pero si no tengo una direccion en utl_files, ya no puedo hacer la recuperacion? Que son esos utl_files?

Saludos,

Tadaki-30 dijo...

hola me gusta tu blog soy desarrolladora en Oracle, me encantaria intercambiar opiniones
Soy de Costa Rica

ibrais@gmail.com

Anónimo dijo...

Hola, me sirvio mucho tu post para comenzar con log miner , pero tengo una consulta, es posible encontrar las transacciones dentro de un determinado rango de fechas?
Ejecute los pasos que mencionas y al final probe lo siguiente:

SQL> EXECUTE sys.DBMS_LOGMNR.START_LOGMNR(DICTFILENAME =>'/usr/tmp/dictionary.dic',STARTTIME =
> TO_DATE('30-Oct-2007 12:30:00','DD-MON-YYYY HH:MI:SS'),ENDTIME => TO_DATE('30-Oct-2007 12:49:00',
'DD-MON-YYYY HH:MI:SS'));
BEGIN sys.DBMS_LOGMNR.START_LOGMNR(DICTFILENAME =>'/usr/tmp/dictionary.dic',STARTTIME => TO_DA

*
ERROR at line 1:
ORA-01291: falta el archivo log
ORA-06512: en "SYS.DBMS_LOGMNR", línea 53
ORA-06512: en línea 1

No entiendo porque me sale este error, cuando ya registre un redolog

Anónimo dijo...

Buenas Tardes,
Interesante la documentación acerca de la herramienta LogMiner Viewer.

Pero tengo una pregunta, sobre los resultados que se muestran despues de buscar las transacciones realizadas sobre una tabla especifica de la base de datos.

Resulta que tengo unos informes en formato html generados con logminer viewer y hay ciertos momentos de trabajo de un usuario en los que aparecen operaciones del tipo UNSUPPORTED, entonces solo aparece este texto para todas las columnas generadas en el archivo y al final me informa qué usuario genera esta transacción.

Qué significado tiene este tipo de operación (UNSUPPORTED) y cómo lo puedo explicar en un informe de auditoria?

Anónimo dijo...

UNSUPPORTED quizás sea porque las tablas contengan datos de tipo LOB...

Unknown dijo...

Hola..

Es un ejemplo de fácil entendimiento.

Mil gracias,

dekano dijo...

Muchas gracias de verdad, mi primera toma de contacto con esto, bien explicado y conseguido ayudarme en el problema que tenia