jueves, 19 de mayo de 2011

Conectarse a la Base de datos cuando cualquier otro metodo no lo permite

Conectarse a la Base de datos cuando cualquier otro metodo no lo permite Te vas a topar situaciones en donde te vas a tratar de conectar a la base de datos y por cualquier metodo que intentas no vas a poder, este metodo es para ayudarte a analizar la razon por la cual no te puedes conectar, se le conoce como metodo preliminar


root $ sqlplus -prelim / as sysdba
SQL*Plus: Release 11.2.0.2.0 Production on Thu May 19 22:14:53 2011
Copyright (c) 1982, 2010, Oracle. All rights reserved.

DBATEST >

o tambien de la siguiente manera


root $ sqlplus /nolog
SQL*Plus: Release 11.2.0.2.0 Production on Thu May 19 22:17:50 2011
Copyright (c) 1982, 2010, Oracle. All rights reserved.

>set _prelim on
>connect / as sysdba
Prelim connection established
DBATEST >

Una vez que te hayas conectado, vamos a hacer un trace para que te ayude a diagnosticar el problema.


DBATEST >oradebug hanganalyze 3
Statement processed.

DBATEST >oradebug setmypid
Statement processed.

DBATEST >oradebug dump systemstate 10
Statement processed.

Como podemos ver en el log, se genero el siguiente archivo trace


Thu May 19 22:19:46 2011
System State dumped to trace file /mount/dump01/oracle/DBATEST/diag/rdbms/dbatest/DBATEST/trace/DBATEST_ora_5145.trc

Conclusion 
Espero que esta pequeña entrada te ayude cuando te enfrentes a esta situacion.

miércoles, 4 de mayo de 2011

Falla al coleccionar estadisticas para un esquema ( ORA-20000 y ORA-06512 Statistics collection failed for all objects in schema )

Aqui de regreso con un post mas, estos ultimos dos meses he estado algo ocupado por eso no he podido mantener el paso de 1 post por semana, pero aqui tengo uno que si se lo topan les puede ayudar en un futuro o un problema actual.

Tengo un proceso personalizado que corre diario buscando objetos que no tienen estadisticas, este proceso llevaba corriendo mas de un año sin ningun problema, y hace unos pocos dias empezo a fallar y ahora si que me agarro por sorpresa este error, pero pudimos arreglarlo despues de investigar un rato.

Lo que sucedio fue que dias atras se corrio un proceso con Datapump, si no conoces esta herramienta de Oracle, es usada para exportar/importar informacion; Este proceso fallo y algunas veces cuando eso sucede, deja una tabla externa, que eso era lo que estaba causando que fallara la coleccion de estadisticas para mi base de datos.

Para poder encontrar y solucionar el error hicimos lo siguiente:
Alteramos nuestra sesion para generar trace del error que estaba marcando, una vez que alteramos la sesion, corremos la generacion de estadisticas.

DBATEST >alter session set events '6512 trace name errorstack level 3';

Session altered.

DBATEST >begin
2 dbms_stats.gather_schema_stats( ownname => 'HR',
3 estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
4 degree => 8,cascade => TRUE,
5 options => 'GATHER EMPTY',
6 method_opt => 'FOR ALL COLUMNS SIZE AUTO' );
7 end;
8 /
*
ERROR at line 1:
ORA-20000: Statistics collection failed for all objects in schema
ORA-06512: at "SYS.DBMS_STATS", line 24189
ORA-06512: at "SYS.DBMS_STATS", line 24130
ORA-06512: at line 2

Como podemos ver en el trace, aqui es donde nos esta diciendo que la tabla externa es la causante de nuestro problema

----- Error Stack Dump -----
ORA-20011: Approximate NDV failed: ORA-29913: error in executing ODCIEXTTABLEOPEN callout
KUP-11024: This external table can only be accessed from within a Data Pump job.
ORA-06512: at "SYS.DBMS_STATS", line 20184

Siguiendo la nota de MOS 336014.1, pudimos limpiar esta tabla, lo primero es ver si el proceso de Datapump no esta realmente corriendo:

DBATEST >SET lines 200
DBATEST >COL owner_name FORMAT a10;
DBATEST >COL job_name FORMAT a20
DBATEST >COL state FORMAT a11
DBATEST >COL operation LIKE state
DBATEST >COL job_mode LIKE state

-- localizar jobs de Data Pump :

DBATEST >SELECT owner_name, job_name, operation, job_mode,
2 state, attached_sessions
3 FROM dba_datapump_jobs
4 WHERE job_name NOT LIKE 'BIN$%'
5 ORDER BY 1,2;

OWNER_NAME JOB_NAME OPERATION JOB_MODE STATE ATTACHED_SESSIONS
---------- -------------------- ----------- ----------- ----------- -----------------
HR SYS_IMPORT_FULL_01 IMPORT FULL NOT RUNNING 0

Despues pasamos a encontrar la tabla maestra de datapump
DBATEST >SELECT o.status, o.object_id, o.object_type,o.owner||'.'||object_name "OWNER.OBJECT"
2 FROM dba_objects o, dba_datapump_jobs j
3 WHERE o.owner=j.owner_name AND o.object_name=j.job_name
4 AND j.job_name NOT LIKE 'BIN$%' ORDER BY 4,2;


STATUS OBJECT_ID OBJECT_TYPE
--------------------- ----------
OWNER.OBJECT
-------------
VALID 44461 TABLE
HR.SYS_IMPORT_FULL_01

Una vez que localizamos la tabla maestra del job, tiramos la tabla, si llegaras a encontrar mas de una tabla, antes de tirarla, cerciorate que estas sean de un proceso de Datapump fallido.

DBATEST >drop table HR.SYS_IMPORT_FULL_01;

Table dropped.

Ahora pasamos a encontrar la tabla externa y de la misma manera tirarla.

DBATEST >set linesize 200 trimspool on
DBATEST >set pagesize 2000
DBATEST >col owner form a30
DBATEST >col created form a25
DBATEST >col last_ddl_time form a25
DBATEST >col object_name form a30
DBATEST >col object_type form a25
DBATEST >
DBATEST >select OWNER,OBJECT_NAME,OBJECT_TYPE, status,
2 to_char(CREATED,'dd-mon-yyyy hh24:mi:ss') created
3 ,to_char(LAST_DDL_TIME , 'dd-mon-yyyy hh24:mi:ss') last_ddl_time
4 from dba_objects
5 where object_name like 'ET$%'
6 /

OWNER OBJECT_NAME OBJECT_TYPE STATUS CREATED LAST_DDL_TIME
------------------------------ ------------------------------ ------------------------- --------------------- -------------------------
HR ET$01A305940001 TABLE VALID 27-apr-2011 13:32:45 28-apr-2010 08:15:28

DBATEST >select owner, TABLE_NAME, DEFAULT_DIRECTORY_NAME, ACCESS_TYPE
2 from dba_external_tables
3 order by 1,2
4 /

OWNER TABLE_NAME DEFAULT_DIRECTORY_NAME ACCESS_TYPE
------------------------------ ------------------------------ ------------------------------ ---------------------
HR ET$01A305940001 DATA_PUMP CLOB

DBATEST >spool off

DBATEST >drop table HR.&1 purge;
Enter value for 1: ET$01A305940001
old 1: drop table HR.&1 purge
new 1: drop table HR.ET$01A305940001 purge

Table dropped.

Una vez que completamos los pasos mencionados arriba, volvemos a correr las estadisticas,y vamos a ver que el proceso termina sin ningun error.

DBATEST >begin
2 dbms_stats.gather_schema_stats( ownname => 'HR',
3 estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
4 degree => 8,cascade => TRUE,
5 options => 'GATHER EMPTY',
6 method_opt => 'FOR ALL COLUMNS SIZE AUTO' );
7 end;
8 /

PL/SQL procedure successfully completed.

Conclusion
Como podemos ver, aunque es simple la solucion, poder encontrar el problema y solucionarlo nos puede llevar algo de tiempo, asi como hay que asegurarnos siempre que falle un proceso de Datapump, limpiar las tablas que genera, aunque este deberia ser algo que Oracle deberia de hacer internamente, pero al dia de hoy no lo hace, asi que con cuidado y espero que te sirva esta entrada.

domingo, 10 de abril de 2011

Un commit hace que mi informacion se escriba en los datafiles?

El otro día recibí la pregunta que si en el momento que hago commit, los datos los encuentro en los datafiles?

Para poder entender esta pregunta, primero debemos conocer un poco los procesos y las estructuras de memoria que tiene Oracle, te invito a que vayas a la entrada Instancia es igual a procesos y memoria para que tengas una mejor idea de varios de los procesos que vamos a hablar aqui.

Lo primero que hay que entender es que el DBWn es un proceso flojo,ya que no es un proceso que cada n segundos este escribiendo los datos del Buffer Cache a los datafiles, si no que es activado por otro proceso (Como CKPT por ejemplo).

Tomemos el siguiente ejemplo,supon que yo siendo el todopoderoso, incremento mi salario de 1 USD a 5 USD en la tabla employees, e inmediatamente despues hago un commit.

Pregunta, si yo ya hice un commit, encontraría el valor de 5 USD en los datafiles?

Antes de responder esta pregunta, vamos a poner otra situación con el mismo ejemplo, en lugar de cometer mis datos después del incremento salarial que me di,decido esperarme el fin de semana para reflexionar en este cambio, solamente dejo la sesión abierta sin cometer los datos.
El lunes que regreso, y verifico los datos directamente en los datafiles, que valor encontraría, 1 o 5 USD?

La lógica me llevaría a decir que, 1 USD, ya que nunca cometí mis datos, cierto?

Una ultima pregunta con este escenario,acuerdate que no hemos cometido los datos,si yo checara los datos en el Online Redo Log, que valor encontraria, 1 o 5 USD?

Si tu respuesta fue 1 USD, seria la mas lógica, ya que no he cometido los datos y no son necesarios para el proceso de recuperación en caso de que mi base de datos se cayera, si respondiste 5 USD, entonces como explicarías el proceso de recuperación en caso de que se haya caído la instancia, si cuando se hace una recuperación los procesos leen del Online Redo Log, y el valor que se encuentra es el de 5 USD?

Antes de empezar, y para que no se te quemen las habas,las respuestas son 1,5 y 5 USD

Vamos a tratar de explicarlo aquí abajo

Crea un tablespace pequeño, en este casa de 1M, y crea en el usuario hr, una tabla llamada prueba_salario, y en esta tabla inserta el dato de salario


TESTDB >create tablespace prueba datafile '/mount/u01/oracle/TESTDB/data/pruebas01.dbf' size 1m;

Tablespace created.

TESTDB >create table hr.prueba_salario (salario varchar2(200)) tablespace prueba;

Table created.

TESTDB >insert into hr.prueba_salario values ('1_USD');

1 row created.

TESTDB >commit;

Commit complete.

Una vez que completes esto, recicla la base de datos, ya que no queremos que nada se encuentre en memoria, y si te fijas, el dato de 1_USD lo puedes ver
en el datafile

oracle@localhost [TESTDB] /mount/u01/oracle/TESTDB/data
root $ strings /mount/u01/oracle/TESTDB/data/pruebas01.dbf

z{|}
5wXTESTDB
PRUEBA
1_USD

Y ahora haz un update a la tabla hr.prueba_salario y realiza un commit, inmediatamente después verifica de nuevo el datafile, y te vas a dar cuenta
que este dato que acabas de actualizar no se encuentra en el datafile, que sigues viendo el valor de 1_USD

TESTDB >update hr.prueba_salario set salario = '5_USD';

1 row updated.

TESTDB >commit;

Commit complete.

oracle@localhost [TESTDB] /mount/u01/oracle/TESTDB/data
root $ strings /mount/u01/oracle/TESTDB/data/pruebas01.dbf

z{|}
5wXTESTDB
PRUEBA
1_USD

En el momento que mandamos llamar al proceso de CKPT, es cuando los buffers "sucios" se escriben a disco, despues de que hagas un checkpoint,
verifica de nuevo el datafile, y te vas a dar cuenta que el datafile esta actualizado con el nuevo valor de 5_USD.


TESTDB >alter system checkpoint;

System altered.

oracle@localhost [TESTDB] /mount/u01/oracle/TESTDB/data
root $ strings /mount/u01/oracle/TESTDB/data/pruebas01.dbf

z{|}
5wXTESTDB
PRUEBA
5_USD

Ahora vamos a hacer otra prueba, tira la tabla prueba_salario, vuelvela a crear, vuelve a insertar el dato de 1_USD y una vez que finalices esto, recicla la base de datos para asegurarnos que no se encuentre nada en memoria.

Ahora vamos a hacer un update a la tabla de prueba salario, y no vamos a hacer un commit, solamente vamos a llamar al proceso de CKPT.

TESTDB >update hr.prueba_salario set salario = '5_USD';

1 row updated.

TESTDB >alter system checkpoint;

System altered.

Si te fijas abajo, el dato de 5_USD es el que se encuentra en el datafile y no el de 1_USD, aunque no hemos hecho un commit de los datos.


oracle@localhost [TESTDB] /mount/u01/oracle/TESTDB/data
root $ strings /mount/u01/oracle/TESTDB/data/pruebas01.dbf

z{|}
5wXTESTDB
PRUEBA
5_USD

Abre una nueva sesión y haz un query a la tabla y te fijaras que el dato de 1_USD es el que te arroja, que es el correcto ya que no hemos cometido los datos


TESTDB >select * from hr.prueba_salario;

SALARIO

------------------------

1_USD

Una de las preguntas que te has de estar haciendo en este momento, es como Oracle sabe que información arrojar, si en el datafile se encuentra el valor de 5_USD. Oracle logra esto a través de un flujo que se llama Consistencia de Lectura (Read Consistency [RC]).

Antes de continuar hay que conocer que es el SCN (System Change Number), este es el punto logico
en el tiempo en el que los cambios se hacen a la base de datos.

El flujo de RC funciona con el SCN para garantizar el orden de las transacciones, cuando lanzaste el query en la sesión nueva, la base de datos determina el SCN registrado en el momento que el query se empezó a ejecutar.

Este select requiere una versión de los bloques de datos que sean consistentes con los cambios que únicamente se encuentran cometidos. Oracle copia los bloques que se encuentran en los bloques actuales a un buffer de datos nuevo y le aplica datos de undo para reconstruir las versiones anteriores de los bloques de datos. A estas copias se le conocen como clones de consistencia de lectura(Consistency Read Clones).

Para saber si la transaccion esta cometida o no, Oracle utiliza una tabla de transacciones llamada lista de transacciones de interes (Interested Transaction List [ITL]), esta lista se encuentra en la cabecera del bloque.

Para terminar y regresar al punto, si sabemos que el DBWn es un proceso flojo, y que aunque haga un commit de mis datos, estos pueden que no se encuentren en los datafiles.

¿De donde toma Oracle la información para esto si se me llegara a caer la base de datos antes de que el CKPT mandara a llamar al DBWn?

La respuesta esta en el Online Redo Log y cuando encuentra el marcador de commit, como ya habíamos platicado de lo que es el Online Redo Log, no voy a entrar mas a detalle en este tema, pero como puedes ver por los ejemplos anteriores, el Online Redo Log, es critico para la consistencia de nuestros
datos.

Conclusion

Espero que con esta explicación puedas comprender la importancia de los Online Redo Logs, ya que si los llegaras a perder, puedes tener perdida de información en tu base de datos, también vimos un poco de como funciona el undo y como se logra la consistencia de lectura a través de sesiones sin cometer.

P.D. Quiero Agradecer a Arup Nanda por permitirme utilizar gran parte de su material para esta entrada, 100 Things You Probably Didn't Know.

Actualización

04/Dec/2012: No me habia fijado que el formato de SQL de esta entrada se habia perdido, asi que se lo volvi a poner.

jueves, 31 de marzo de 2011

Instancia es igual a Procesos y Estructuras de memoria

La definicion de una instancia es sencilla y basica, es un conjunto de estructuras de memoria que manejan los archivos de la base de datos, cuando inicia la instancia, con ella inician procesos de fondo (Background Process), como el LGWR, PMON, etc.

Importante saber que al menos una base de datos activa o mejor dicho que esta corriendo, debe de tener una instancia asociada. De la misma manera, como la instancia existe en memoria y la base de datos existe en disco, una instancia puede existir sin una base de datos y una base de datos puede existir sin una instancia, si no me crees esto, haz la prueba, arranca la instancia en modo nomount y veras que sin existir los datafiles,controlfiles y redo logs puedes iniciar la instancia


TESTDB >startup nomount

ORACLE instance started.
Total System Global Area 1369989120 bytes
Fixed Size 2158184 bytes
Variable Size 268439960 bytes
Database Buffers 1090519040 bytes
Redo Buffers 8871936 bytes

oracle@localhost [TESTDB] /mount/dba01/oracle/TESTDB/admin
oracle $ ps -eaf | grep TESTDB

oracle 27411 1 0 01:21:35 ? 0:00 ora_pmon_TESTDB

oracle 27448 1 0 01:21:37 ? 0:00 ora_ckpt_TESTDB

oracle 27435 1 0 01:21:37 ? 0:00 ora_dia0_TESTDB

oracle 27439 1 0 01:21:37 ? 0:00 ora_dbw0_TESTDB

oracle 27454 1 0 01:21:37 ? 0:00 ora_mmon_TESTDB

oracle 27415 1 0 01:21:35 ? 0:00 ora_psp0_TESTDB

oracle 27444 1 0 01:21:37 ? 0:00 ora_dbw1_TESTDB

oracle 27431 1 0 01:21:37 ? 0:00 ora_diag_TESTDB

oracle 27446 1 0 01:21:37 ? 0:00 ora_lgwr_TESTDB

oracle 27452 1 0 01:21:37 ? 0:00 ora_reco_TESTDB

oracle 27450 1 0 01:21:37 ? 0:00 ora_smon_TESTDB

Aqui abajo esta una pequeña grafica de como se conforma una instancia:


Y debido a lo que platicamos arriba, es lo que permite la configuracion para RAC (Real Application Cluster), asi tambien es importante saber que una instancia no puede tener asociada una sola base de datos a la vez, o sea que no puedes montar dos base de datos en una instancia.

Memoria
La memoria SGA tiene 3 estructuras básicas:

Database buffer cache.- Es el área de memoria que almacena copias de los bloques de datos leídos de los data files.Tambien a esta área se le conoce nada mas como Buffer Cache. Esta seccion de la memoria tiene tres estados.
  • Sin Usar (Unused).-El buffer esta disponible por que nunca se ha usado o actualmente esta sin usar.
  • Limpia (Clean).-Este buffer fue usado previamente, y ahora contiene una version consistente del bloque de datos en un punto en tiempo. El bloque contiene datos, pero este se puede decir que esta limpio, ya que no se le necesita hacer un checkpoint a los datos.
  • Sucia (Dirty).-El buffer contiene datos que no han sido escrito a disco, Oracle necesita hacer un checkpoint del bloque de datos antes de reusarlo.
  • Para manejar estos estados, Oracle tiene un algortimo llamado LRU (Least Recently Used), lo que hace este algoritmo es sacar del buffer a los bloques de datos menos usados y que ya se le hayan hecho un checkpoint para asi poder subir al Buffer Cache nuevos datos y evitar sacar del Buffer Cache los datos que se usan con frecuencia.

Shared Pool .- Esta área de memoria guarda SQL analizado (Parsed),parámetros del sistema y el diccionario de datos (Data Dictionary Cache y Library Cache).

Redo Log Buffer.- Esta estructura de memoria en el SGA, que guarda los registros de Redo, estos contienen la información necesaria para reconstruir los cambios hechos por DDLs o DMLs a la base de datos.

Procesos
Existen varios que son obligatorios, como los mencionados aqui abajo, de la misma manera existen muchos procesos que se inician una vez que añades alguna funcionalidad, como el ARCn, que es cuando la base de datos esta en modo archivelog.

PMON.- La funcionalidad de este proceso es la de monitorear que los demás procesos de la instancia estén corriendo, a su vez es responsable de limpiar el Database Buffer Cache y limpiar recursos que el cliente haya utilizado.

SMON.-La tarea principal de este proceso es la de limpieza a nivel sistema, y también una de las tareas principales de este proceso es llevar a cabo la recuperación al iniciar la instancia cuando anteriormente finzalizo de una manera abrupta, como un shutdown abort o un crash del servidor.

CKPT.-Su función es la de actualizar las cabeceras de los control files y de los data files, con información de Checkpoint (SCN, Posición de Checkpoint, etc), a su vez la avisa al DBWn que debe de escribir los bloques del Buffer Cache a disco. Muy importante saber, que el CKPT no escribe los datos, ni al Redo Log ni a los data files.

DBWn.-Este proceso escribe los contenidos sucios del buffer Cache, a este proceso se le conoce como un proceso flojo, ya que por si solo no escribe a disco, este unicamente escribe a disco cuando no hay bloques de datos limpios en el buffer cache o cuando CKPT le informa que debe hacerlo.

LGWR.- De lo que se encarga es de escribir los Redo Log Buffers a disco (Online Redo Log). Este proceso utiliza un método que se le conoce como Fast Commit. Cuando un usuario ejecuta un commit, a la transacción se le asigna un SCN (System Change Number), LGWR pone una marca de commit en el Buffer Cache e inmediatamente escribe a disco, cuando se han escrito estos datos en el Online Redo Log, el proceso actualiza el Buffer Cache haciendo mención de que estos ya se escribieron a disco.

Conclusion
Espero que esta pequeña explicación te ayude a comprender la diferencia entre la Instancia y lo que en Oracle se conoce como Base de Datos. De la misma manera los procesos basicos y memoria basica de la instancia, para los procesos y la memoria existen mas de los mencionados aqui, pero estos son los minimos necesarios en una configuracion de Oracle.

miércoles, 30 de marzo de 2011

Que es un Online Redo Log

Que es Online Redo Log?
El Online Redo log, es una estructura fisica que consiste de minimo de dos archivos, estos a su vez pueden estar multiplexados en dos o mas copias identicas, que a estos se le conocen como miembros de un grupo de Redo log. Como mencionamos, el Online Redo Log consiste de minimo dos archivos, esto permite que Oracle escriba en un archivo de Online Redo Log mientras el otro se archiva (Cuando mencionamos archivar, es si la base de datos se encuentra en modo ARCHIVELOG).
En los Online Redo logs se almacenan registros de Redo, los cuales estan conformados por vectores de cambio (change vectors), cada uno de estos vectores describe los cambios a un bloque de datos.

Todos los registros de tipo redo tiene metadata relevante al cambio, incluyendo:
  • SCN y la estampa de tiempo del cambio
  • El ID de la transaccion que ha generado el cambio
  • SCN y la estampa de tiempo cuando la transaccion fue cometida (si es que fue cometida)
  • Tipo de operacion que efectuo el cambio
  • Nombre y tipo del segmento de dato modificado

Los Online Redo Log son usados unicamente en el proceso de la recuperación de la base de datos.
Basicamente,lo que hay que entender como principio, es que cuando algun DML (insert,update o delete) o un DDL (alter, create, drop) sucede en nuestra base de datos, Oracle registra los cambios en memoria, en un buffer llamado Redo Log Buffer, que con este buffer hay un proceso asociado llamado LGWR.

El proceso LGWR de lo que se encarga es de escribir de la estructura de memoria (Redo) Log Buffer a los Online Redo Logs, y muy importante es saber cuales son las circunstancias que hacen que el LGWR escriba al Online Redo Log:
  • Cuando un usuario hace un commit a la transaccion
  • Cuando sucede un cambio (log switch) de archivo de Redo Log
  • Cuando han pasado tres segundos desde la ultima escritura del LGWR hacia el Online Redo Log
  • Cuando el Redo Log Buffer esta 1/3 lleno o contiene mas de 1Mb de datos en el buffer.
  • Cuando el proceso DBWn necesita escribir datos del Database Buffer Cache hacia disco.
El proceso LGWR escribe a los archivos de Online Redo Log de manera circular, cuando el LGWR escribe en el ultimo archivo de Online Redo Log disponible, el LGWR se regresa a escribir al primer archivo de Online Redo Log.

Ahora que ya vimos que es , y como mencionabamos arriba, los Online Redo Logs, son unicamentes usados en el proceso de recuperacion de la base de datos.

En el proceso de recuperacion, se presenta tanto lo que es aplicar cambios cometidos no reflejados en los datafiles, a esto se le conoce como Roll Forward, y remover los cambios aplicados no cometidos de los datafiles, a esto se le conoce como Roll Back.

Suena un poco confuso, pero realmente no lo es, lo unico que hay que saber es que cuando se realiza un commit, Oracle añade un Marcador de Commit en el redo log buffer, asi es como Oracle sabe que datos son cometidos y cuales no.

Aqui un pequeño algoritmo de como es el proceso de recovery, este lo tome del blog de Arup Nanda, no me lo acredito, solamente lo estoy traduciendo:

Leer las entradas de tipo Redo Log, empezando con el mas antiguo
Verificar el numero SCN del Cambio
Buscar el Marcador de Commit.
Si el marcador es encontrado, entonces los datos han sido cometidos.
Si es encontrado, entonces buscar los cambios en los datafiles (via el numero SCN)
    ¿Cambios estan reflejados en los datafiles?
    Si si, entonces brinca
    Si no,aplicar los cambios a los datafiles (Roll Forward)
Si no es encontrado,entonces los datos estan sin cometer,buscar los cambios en los datafiles
    ¿Cambios estan reflejados en los datafiles?
    Si no, entonces brinca
    Si si, entonces hacer un update a los datafiles con los datos antes del cambio (Roll Back)

Para ver la informacion que tiene los redo logs, puedes hacer una sesion de logminer, que eso lo veremos en otra entrada, pero por el momento te esneño un ejemplo de la informacion que puedes ver.

En una sesion con el el usuario HR, voy a crear una tabla llamada BLAH, y voy ver la informacion de la transaccion, una vez que veo esta informacion voy a darle commit para finalizar la transaccion.

TESTDB >create table blah( name varchar2(100), num number);

Table created.

TESTDB >insert into "HR"."BLAH"("NAME","NUM") values ('Texto Nada Mas Probar Que Inserto','60671');

1 row created.

TESTDB >select dbms_transaction.local_transaction_id from dual;

LOCAL_TRANSACTION_ID
--------------------------------------------------------------------------------
47.30.24303

TESTDB >commit;

Commit complete.

Ahora uso la utileria de log miner para poder ver esta informacion del redo log utilizando el XID de la transaccion de arriba, y aqui podemos ver la informacion del SQL_REDO y SQL_UNDO

column sql_redo format a30 word_wrapped
column sql_undo format a30 word_wrapped
column seg_owner format a12
select seg_owner,SQL_REDO,SQL_UNDO FROM V$LOGMNR_CONTENTS where XIDUSN=47 and XIDSLT=30 and XIDSQN=24303

SEG_OWNER SQL_REDO SQL_UNDO
------------ ------------------------------ ------------------------------
set transaction read write;
HR insert into delete from "HR"."BLAH" where
"HR"."BLAH"("NAME","NUM") "NAME" = 'Texto Nada Mas
values ('Texto Nada Mas Probar Que Inserto' and "NUM"
Probar Que Inserto','60671'); = '60671' and ROWID =
'AAATuqAAEAAAA+YAAA';

commit;

Conclusion
Espero que con esta pequeña informacion de lo que es un Redo Log y con la entrada anterior de lo que es un registro tipo undo puedas ver la diferencia entre ambos y su uso especifico de estos.

miércoles, 16 de marzo de 2011

Clonar con RMAN una Base de Datos sin conexion al Catalogo y a la Base de datos de Origen

Uno de las tareas comunes y a veces repetitivas que tenemos para los usuarios de desarrollo, es la necesidad de clonar una base de datos de produccion hacia una de desarrollo, pero uno de los problemas que presentaba el comando DUPLICATE de rman era que para poder hacerlo tenias que tener una conexion a la base de datos origen (TARGET DATABASE) , que pasaba si por consecuencias del destino no tenias o no podias conectarte a esta base de datos, realmente te ponia en una situacion en donde te las tenias que ingeniar para poder clonar tu base de datos.

En la version de 11gR2 puedes clonar tu base de datos sin que tengas que conectarte a la base de datos origen y tampoco al catalogo, solamente con que tengas acceso al respaldo es mas que suficiente, claro tomando en cuenta de que es un respaldo consistente y que tambien se hayan respaldado los archive logs, para un ejemplo de como hacer un respaldo lo puedes encontrar en nuestra entrada  Respaldos con RMAN - Parte I .Vamos a ver como se hace

Para empezar tenemos que asegurarnos que el respaldo sea visible en el servidor donde se encuentra la base de datos auxiliar (AUXILARY DATABASE), ya sea copiando los archivos del servidor donde se encuentra al servidor de la base de datos auxiliar o por un NFS share.

El siguiente paso es asegurarnos que tenemos todas nuestras variables de ambiente definidas para la base de datos auxiliar, como ORACLE_HOME,ORACLE_SID, ORACLE_BASE, y cualquier otra variable que use tu auxiliar.

Importante, la siguiente variable de ambiente tiene que estar presente, ya que si no te puedes enfrentar al Bug 1300348.1 (Recovery Time For Rman Duplication Does Not Match Specified Until Time Clause). En donde lo que sucede es se trunca la fecha y es como si fueran las 00:00 hrs de la fecha a la que vas a hacer la recuperacion.

NLS_DATE_FORMAT='DD-MON-YYYY HH24:MI:SS'
export NLS_DATE_FORMAT


Tambien tenemos que definir nuestro archivo de parametros init_AUXILIAR_BD.ora (pfile). Puedes tomar como ejemplo el archivo de parametros de la base de datos Origen, asegurandote que el parametro db_name= AUXILIAR_BD y control_files = DIRECTORIO_CTL_AUXILIAR_BD

Asegurate de que $ORACLE_HOME/bin se encuentre en el PATH tambien
ejemplo
export PATH=$ORACLE_HOME/bin:$PATH


Ahora vamos a copiar el archivo de password de la base de datos origen a nuestra auxiliar, este archivo se encuentra en $ORACLE_HOME/dbs para unix o $ORACLE_HOME/database para windows, lo puedes encontrar con el nombre de orapwNOMBRE_BD.

Una vez que hayamos completado los pasos anteriores,vamos a crear el archivo spfile del pfile initAUXILIAR_BD.ora que configuramos arriba y vamos a arrancar la base de datos auxiliar en modo nomount

oracle $ sqlplus

SQL*Plus: Release 11.2.0.2.0 Production on Thu Mar 17 01:00:23 2011

Copyright (c) 1982, 2010, Oracle. All rights reserved.

Enter user-name: /as sysdba

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
With the OLAP, Data Mining and Real Application Testing options

TESTDB >create spfile from pfile='/mount/dba01/oracle/TESTDB/pfile/initTESTDB.ora';

File created.

TESTDB >startup nomount
ORACLE instance started.

Total System Global Area 3658891264 bytes
Fixed Size 2163680 bytes
Variable Size 1392516128 bytes
Database Buffers 2248146944 bytes
Redo Buffers 16064512 bytes

TESTDB >exit

Ahora vamos a crear el script de rman para hacer la clonacion, que te puedes ayudar del siguiente query, corriendolo en la base de datos origen para hacer los cambios de directorio, este lo utilizo en Unix

SELECT 'set newname for datafile '
|| a.file#
|| ' to ''&aux_data_mnt'
|| SUBSTR (a.NAME, INSTR (a.NAME, '/', -1, 1) + 1)
|| ''';'
FROM v$datafile a, v$tablespace b
WHERE a.ts# = b.ts# and
a.file# IN (SELECT DISTINCT file#
FROM v$backup_datafile)
UNION ALL
SELECT 'set newname for tempfile '
|| a.file#
|| ' to ''&aux_data_mnt'
|| SUBSTR (a.NAME, INSTR (a.NAME, '/', -1, 1) + 1)
|| ''';'
FROM v$tempfile a;

Del resultado de query de arriba, voy a construir el script de rman, llamado clone_TESTDB.rmn, toma en cuenta que nos vamos a conectar a la base de datos auxiliar, asi que tenemos que alojar los canales auxiliares.

RUN
{
ALLOCATE AUXILIARY CHANNEL CH1 TYPE DISK ;
ALLOCATE AUXILIARY CHANNEL CH2 TYPE DISK ;
ALLOCATE AUXILIARY CHANNEL CH3 TYPE DISK ;
set newname for datafile 1 to '/mount/u01/oracle/TESTDB/data/system01.dbf';
set newname for datafile 2 to '/mount/u01/oracle/TESTDB/data/sysaux01.dbf';
set newname for datafile 3 to '/mount/u01/oracle/TESTDB/data/def01.dbf';
set newname for datafile 4 to '/mount/u01/oracle/TESTDB/data/undorbs1_1.dbf';
set newname for tempfile 1 to '/mount/u01/oracle/TESTDB/data/temp01.dbf';
DUPLICATE DATABASE TO TESTDB
UNTIL time "to_date('12-MAR-201112:57:29','dd-MON-yyyyhh24:mi:ss')"
BACKUP LOCATION '/mount/copy01/SOURCEDB'
logfile
group 1 (
'/mount/u01/oracle/TESTDB/log/redo01g01.log',
'/mount/u01/oracle/TESTDB/log/redo02g01.log'
) size 50M,
group 2 (
'/mount/u01/oracle/TESTDB/log/redo01g02.log',
'/mount/u01/oracle/TESTDB/log/redo02g02.log'
) size 50M,
group 3 (
'/mount/u01/oracle/TESTDB/log/redo01g03.log',
'/mount/u01/oracle/TESTDB/log/redo02g03.log'
) size 50M
;
}

Si te fijas en el script, la clave se encuentra en la seccion del comando DUPLICATE,
DUPLICATE DATABASE TO TESTDB
UNTIL time "to_date('12-MAR-201112:57:29','dd-MON-yyyyhh24:mi:ss')"
BACKUP LOCATION '/mount/copy01/SOURCEDB'
Ya que no estamos diciendo que sea el duplicado directamente de la base de datos TARGET, sino que estamos diciendole a rman donde se encuentra nuestro respaldo. Algo que debes saber es que cuando clonas una base de datos sin conexion al catalogo y a tu base de datos origen, la unica clausula UNTIL que puedes usar es TIME, no puedes usar SCN o SEQUENCE.
Ahora si ya estas listo para hacer la clonacion, conectate con la utileria de rman en la base de datos auxiliar, y corre el script creado arriba

oracle $ rman auxiliary /

Recovery Manager: Release 11.2.0.2.0 - Production on Thu Mar 17 02:38:44 2011

Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.

connected to auxiliary database: TESTDB (not mounted)

RMAN>@clone_TESTDB.rmn

Conclusion

Esta nueva manera de hacer una clonacion, ta va a ayudar a mitigar errores, ya que no es necesario conectarte a la base de datos de origen, y de la misma manera, si la base de datos origen no esta disponible, vas a poder clonar tu base de datos.

jueves, 10 de marzo de 2011

Tratas de conectarte como sysdba y no puedes por el error Ora-12547

Aqui de regreso al blog, les pido mil disculpas por no actualizarlo en el ultimo mes, pero estuve viajando y a su vez en un proceso de upgrade a 11.2.0.2 muy pesado. Tocando el tema de este upgrade, ando desarrollando unos scripts en donde tengo que hacer un clon de la base de datos en vivo, esto es sin la nueva funcionalidad de RMAN en 11g.

Haciendo pruebas con este script que les platico, en pruebas, acabe borrando todos los datafiles, controlfiles y redologs!!! Esto si que es preocupante si fuera la base de datos de produccion, pero como era una de pruebas, no pasa nada, el problema surgio cuando tratando de recrear la base de datos, no me dejaba conectarme ni como sysdba, marcando el error ORA-12547.

oracle $ sqlplus

SQL*Plus: Release 11.2.0.2.0 Production on Thu Mar 10 22:39:43 2011

Copyright (c) 1982, 2010, Oracle. All rights reserved.

Enter user-name: /as sysdba
ERROR:
ORA-12547: TNS:lost contact

Cual es mi sorpresa que al buscar informacion de los procesos de la base de datos en mi servidor, veo que ninguno esta corriendo

ejemplo
oracle $ ps -eaf | grep TESTDB | grep -v "grep" | wc -l
       0

Despues de unos cuantos dolores de cabeza tratando de averiguar que fue lo que me estaba impidiendo acceder desde sqlplus a mi instancia, por cierto teniendo todas las variables de ambiente correctas, me di cuenta de que los segmentos de memoria compartida y los semaforos en Unix seguian presentes.

Oracle en 9i,10g y 11g trae una utileria llamada sysresv que nos permite saber que semaforos y segmentos de memoria compartida esta siendo utilizada por nuestra instancia.

$ORACLE_HOME/bin/sysresv

Una vez que corri e identifique los segmentos de memoria compartida y los semaforos que estaban presentes para mi instancia

oracle $ $ORACLE_HOME/bin/sysresv

IPC Resources for ORACLE_SID "TESTDB" :
Shared Memory:
ID KEY
1073741917 0xfc4002bc
Semaphores:
ID KEY
2130706467 0x0b90e3f0
67108901 0x0b90e3f1
1711276072 0x0b90e3f5
1543503922 0x0b90e3f6
1828716596 0x0b90e3f7
Oracle Instance not alive for sid "TESTDB"

Me di a la tarea de removerlos con el comando "ipcrm", de las siguientes dos maneras, toma en cuenta que mi prompt en unix es "oracle $"

oracle $ ipcrm -m [shared_memory_ID]

oracle $ ipcrm -s [semaphore_ID]

Ahora si, despues de que los segmentos de memoria y semaforos no estaban presentes, pude acceder a sqlplus sin ningun problema, pudiendo arrancar mi instancia sin ningun inconveniente

oracle $ sqlplus

SQL*Plus: Release 11.2.0.2.0 Production on Thu Mar 10 23:07:51 2011

Copyright (c) 1982, 2010, Oracle. All rights reserved.

Enter user-name: /as sysdba
Connected to an idle instance.

TESTDB> startup nomount
ORACLE instance started.

Total System Global Area 2088402944 bytes
Fixed Size 2159904 bytes
Variable Size 721423072 bytes
Database Buffers 1342177280 bytes
Redo Buffers 22642688 bytes
TESTDB>

Conclusion
Espero que este pequeño ejemplo les ayude cuande se les presente esta situacion, aunque no es algo que sucede seguido, cuando sucede puede ser un dolor de cabeza arreglarlo y atacarlo.