Primero que nada, debemos conocer lo que es una transaccion.
Que es una Transaccion?
Una transacción es una unidad lógica y atómica de trabajo que contiene una o más sentencias de SQL. Una transaccion agrupa operaciones SQL, de forma que, o a todas las operaciones se le hace un commit, lo que significa que se aplican a la base de datos, o a todas se hace un rollback, lo que significa que se deshacen de la base de datos. Una transaccion debe de tener las propiedades de ACID
Que es un registro Undo?
Basicamente es informacion que es utilizada por Oracle para hacer un rollback (deshacer), a los cambios que hemos hecho a nuestros datos en una transaccion y principalmente tiene los siguientes tres usos:
- Deshacer los datos en nuestra transaccion cuando ejecutamos el comando ROLLBACK
Cuando ejecutamos un rollback,los registros de Undo son usados para deshacer los cambios en la Base de Datos a nuestra transaccion que no ha efectuado un commit. - Poder tener consistencia de lectura de datos
Oracle utiliza los registros de tipo Undo para mantener una imagen consistente de los datos, mientras son modificados por otro usuario.
- Recuperar la Base de Datos
Los registros de tipo Undo son usados en la recuperacion de la Base de Datos, para deshacer cualquier cambio en nuestros datos a los que no se haya efectuado commit y se encuentre en los datafiles.
TESTDB >select tablespace_name
from dba_tablespaces where contents='UNDO';
TABLESPACE_NAME
------------------------------
UNDOTBS
from dba_tablespaces where contents='UNDO';
TABLESPACE_NAME
------------------------------
UNDOTBS
En este tablespace se van a almacenar unicamente segmentos de tipo undo, que a su vez este segmento esta compuesto de minimo dos undo extents,los segmentos de tipo undo son escritos en ellos de forma circular.
En este tipo de tablespace no podemos almacenar una tabla o un indice, el mismo manejador de base de datos no lo permite. Tambien hay que saber que la base de datos nos permite tener mas de un tablespace de tipo undo pero solamente uno puede estar activo a la vez.
Existe dos tipos de manejo de los registros de undo, ya sea de tipo Manual o Automatico, que el default en 11g es Automatico.En el modo Automatico, los registros de undo son manejados en lo que se conoce como segmentos de undo, en el modo manual, los registros de undo se manejan en segmentos de rollback y no se utiliza el tablespace de tipo undo.
La informacion de tipo undo se divide en tres:
- Informacion Undo Uncommited o Active (Sin Cometer)
Da soporte a una transaccion en ejecución, y es requerida si un usuario quiere efectuar un rollback o si la transaccion falla. Este tipo de información nunca es sobreescrita - Informacion Undo Commited o Unexpired (Cometida)
Esta información ya no es requerida por la transacción, pero es necesaria para cumplir con el intervalo de tiempo definida en el UNDO_RETENTION (veremo mas abajo la definicion de este). - Informacion Undo Expired (Expirada)
Esta información ya no es requerida por una transacción y puede ser sobreescrita por la siguiente transacción activa.
Oracle usa una retencion de undo (Undo Retention) manejada en segundos, cuando el tablespace de tipo undo se maneja con la opcion AUTOEXTEND, Oracle retiene la informacion de tipo undo por el tiempo minimo que el parametro UNDO_RETENTION tiene, nada mas que hay un detalle a saber, que si el tablespace ya no tiene suficiente espacio para crecer, va a empezar a utilizar espacio que ocupa la información sin expirar (UNEXPIRED), que esto puede causar un error de tipo ORA-01555.
Ahora que ya sabemos que son, que puedo hacer con esta información?
Vamos a ver un pequeño ejemplo con el usuario hr y vas a poder ver una transacción y el espacio que esta consumiendo de undo.
Primera que nada vamos a verificar el SID tenemos asignado y crear una tabla llamada prueba
TESTDB >select sys_context('USERENV','SID') from dual;
SYS_CONTEXT('USERENV','SID')
----------------------------------------------------------------
69
TESTDB >create table prueba (idprueba number);
Table created.
SYS_CONTEXT('USERENV','SID')
----------------------------------------------------------------
69
TESTDB >create table prueba (idprueba number);
Table created.
Con el siguiente query,verificamos que ninguna transacción esta activa en nuestra sesion, el resultado debe de ser un valor nulo.
TESTDB >select dbms_transaction.local_transaction_id from dual;
LOCAL_TRANSACTION_ID
--------------------------------------
Luego creamos un pequeño bloque de pl/sql que inserte datos en la tabla que creamos, y es muy importante que no le des commit
TESTDB >begin
2 for i in 1..10000 loop
3 insert into prueba values (i);
4 end loop;
5 end;
6 /
PL/SQL procedure successfully completed.
Volvemos a verificar la transacción, y te vas a dar cuenta que como hicimos un insert y no hemos hecho commit, nos regresa un resultado, significando que a nuestra transacion se le asigno un identificador o XID
TESTDB >select dbms_transaction.local_transaction_id from dual;
LOCAL_TRANSACTION_ID
--------------------------------------
47.29.15324
Estos tres numeros son en el orden en que aparecen:
- El identificador del segmento undo donde la transaccion registra su informacion undo.
- El numero de Slot undo en el segmento undo
- El numero secuencial en el Slot de undo
Pero esta información que te muestro arriba, dado que es util saber, normalmente tenemos que ver transacciones que no nos pertenecen, por eso existe una vista llamada v$transaction, en donde podemos verificar transacciones que esta sucediendo en otra parte. Y aqui vas a encontrar tres campos que se te van a hacer muy familiares
- XIDUSN.-El identificador del segmento undo donde la transaccion registra su informacion undo.
- XIDSLOT.-El numero de Slot undo en el segmento undo
- XIDSQN.-El numero secuencial en el Slot de undo
Con el query que se encuentra abajo, puedes ver la relacion con la sesion y la cantidad de undo en megas que esta utilizando la sesion:
select r.name,s.sid,s.serial#,s.module,
to_char(s.logon_time, 'mm/dd/yy hh24:mi:ss') as login_time,
xidusn, xidslot, xidsqn,
t.used_ublk * to_number(x.value)/(1024*1024) as undo_mb
from v$session s,v$transaction t,v$rollname r,v$parameter x
where s.saddr = t.ses_addr and r.usn = t.xidusn
and x.name = 'db_block_size';
Rollback Segment SID,Serial Module Login Time XIDUSN XIDSLOT XIDSQN Undo MB
--------------------- ------------ -------------------- ----------------- ---------- ---------- ---------- ------------
_SYSSMU47_1546937756$ 69,1043 SQL*Plus 01/18/11 18:35:40 47 29 15324 .9141
--------------------- ------------ -------------------- ----------------- ---------- ---------- ---------- ------------
_SYSSMU47_1546937756$ 69,1043 SQL*Plus 01/18/11 18:35:40 47 29 15324 .9141
Conclusion
Conocimos lo que era una transacción, asi como lo que es la definición de undo, de la misma manera que una vez que una transacción inicia, se guarda en un registro tipo undo, la informacion antes de ser cometida (UNCOMMITED) para poder hacer un rollback y tambien para tener consistencia en la lectura de datos una vez que esta fue cometida (COMMITED).
Hola René, soy un fiel seguidor de su blog, me parece muy claras sus explicaciones, lo felicito.
ResponderBorrarAprovecho para realizarle una consulta conceptual que siempre me trae confusiones...
Mi duda es, ¿en donde se guarda primero la información en los redo logs o en el undo?.
Según tengo entendido en los redo también se guarda información sin comitear y es lo primero que se escribe para luego pasar a los datafiles definitivamente. Pero me confunde el hecho de que en el undo se tiene información para soportar la consistencia con lo cual sospecho que este debería ser el primer lugar del disco donde Oracle escribe.
Muchas gracias.
Facundo (Argentina)
Hola Facundo
ResponderBorrarAqui ya de regreso al blog, sabes que estoy en el proceso de un upgrade muy fuerte que me quito un mes y medio, pero ahora voy a hacer una entrada, en donde mencione exactamente esto que me estas preguntando, la intencion de explicar primero que es el undo y que es el redo, para cerrar con lo que me preguntas
Excelente Blog Felicidades!
ResponderBorrar