ISSN: 1579-0223
 
Sentience Research
REDcientífica
· Misión de REDcientífica
· Contacto
· Condiciones de publicación
· Consultar todos los documentos
· Consultar todos los autores
· Acceso usuarios registrados
· English version


PORTADAS
40  41  42  43  44  45  46  47  48  49  50  51  52  53 

BOLETINES
40  41  42  43  44  45  46  47  48  49  50  51  52  53 

TEMAS



ENLACES

Solución al problema "snapshot too old" en Bases de Datos Oracle
El error Oracle ORA-01555: snapshot too old

Patricia Peña Cobo
http://www.tecsidel.es
Directora del Centro de Formación y Consultora del Centro de Tecnología Oracle. Tecsidel
 
ImprimirEnviar

En muchas ocasiones es difícil determinar por qué se ha producido el error, y cómo evitarlo en el futuro. Pero lo peor de todo es que es más probable que se produzca cuando se están ejecutando queries largas, por lo que el volver a procesarlas de nuevo supondrá una gran pérdida de tiempo. Con las pautas presentadas en este artículo se intentará prevenir y corregir este error para los diferentes casos.



Objetivo

En este trabajo intentaremos analizar las diferentes causas que pueden producir el error "ORA-01555:snapshot too old" relacionado con el número o tamaño de los segmentos de rollback de la base de datos.

Dicho error aparece documentado en el manual de errores de Oracle con el siguiente texto:

ORA-01555 snapshot too old: rollback segment number [string] with name "[string]" too small
Cause: Rollback records needed by a reader for consistent read are overwritten by other writers.
Action: Use larger rollback segments.


Funcionamiento De Los Segmentos De Rollback

Los segmentos de rollback son un tipo de objeto que cumplen una serie de funciones dentro la base de datos:

  • permiten deshacer transacciones total o parcialmente mediante las sentencias rollback; y rollback to <savepoint>;
  • se emplean durante la recuperación de transacciones en caso de fallo de instancia: si cae la instancia de BD, durante el siguiente arranque se desharán automáticamente las transacciones no confirmadas. Transaciones no confirmadas son aquellas que pueden haber escrito sus modificaciones a disco durante un checkpoint anterior a la caída de la instancia de BD, pero que realmente no han confirmado los cambios y por tanto no deben perdurar en la BD.
  • permite que se cumpla la consistencia en lectura entre transacciones: esta es la parte que puede producir el error de "copia demasiado antigua".


Consistencia en lectura entre transacciones

Cada usuario tiene una vista consistente de los datos, incluyendo los cambios realizados por las transacciones del propio usuario y las de los demás usuarios.

Esto significa que hay que mantener mecanismos de bloqueo y almacenamiento de valores antiguos hasta que finalizan las transacciones, asegurando que:

  • Cada operación durante su ejecución ve los datos tal y como estaban al comenzar la ejecución.
  • Una transacción escritora bloquea las filas que va a modificar y escribe los valores antiguos en el segmento de rollback que le corresponde, de forma que los procesos lectores que vayan a acceder a dichas filas puedan consultar esos valores antiguos del segmento de rollback. Hasta que la transacción no haga commit, las demás no pueden ver los nuevos valores.

Nota: la transacción escribe en rollback los valores antiguos y en el bloque de datos de la tabla los nuevos, creando además en dicho bloque de datos una entrada de transacción que indica dónde ir a leer los valores antiguos de la fila que está siendo modificada (una referencia a su segmento de rollback).

El problema de "imagen demasiado antigua" se debe a que los valores antiguos que se han creado en el segmento de rollback hacen falta para la consistencia de las operaciones lectoras, pero a veces mientras se está ejecutando la operación lectora el valor antiguo desaparece del segmento de rollback, por lo que no se cumple la consistencia de datos dentro de la propia operación lectora (pues no consigue todos los datos con valores referentes al mismo instante de tiempo), y por tanto se produce el error "ORA-01555: snapshot too old".

¿Por qué desaparece el valor antiguo del segmento de rollback? La respuesta está en la estructura y funcionamiento de este tipo de segmentos: la escritura en ellos es cíclica reutilizando el espacio que estaba siendo utilizado por las transacciones que ya hayan hecho commit o rollback.

Por tanto, puede ocurrir que una consulta muy larga precise que los datos de rollback se mantengan durante mucho tiempo para consistencia de datos dentro de la propia consulta, pero la transacción que los estaba actualizando hace commit; a partir de ese instante, cualquier otra transacción que tenga asignado ese mismo segmento de rollback podrá machacar los valores antiguos, por lo que la consulta no podrá obtenerlos de ningún otro sitio y se producirá el error.

Existe otro caso en el que se puede producir error, y es cuando quizá no ha desaparecido la información de rollback, pero sí ha desaparecido la entrada de transacción de la cabecera de rollback que indica dónde ir a leer los datos de rollback para una transacción.


System Change Number (SCN)

El número de cambio del sistema o SCN es un valor que se incrementa automáticamente y no llega a reutilizarse nunca. El SCN identifica de forma única a una versión de la Base de Datos confirmada.

Cada vez que un usuario confirma una transacción, Oracle memoriza un nuevo SCN. Uno de los lugares donde se pueden consultar los SCN es en el fichero alert.log, y se pueden usar por ejemplo para hacer recuperaciones incompletas hasta un SCN determinado teniendo la base de datos en modo Archivelog.

Oracle utiliza los SCNs en los ficheros de control, cabeceras de ficheros de datos, ficheros de redo log, y en el algoritmo de consistencia en lectura.


Relación entre el error ORA-01555 y el SCN

El error ORA-01555 significa que ha fallado una lectura consistente (a través de rollback para consistencia en lectura) sobre un bloque de BD determinado.

Cuando comienza una transacción o consulta se memoriza el SCN actual. Este SCN sirve como marca de tiempo para la consulta o transacción, ya que debe ver una imagen consistente de la BD en ese instante de tiempo. A esa marca de tiempo se le denomina snapshot SCN.

Cada bloque involucrado en la consulta o transacción debe reflejar el estado de la BD en ese instante de tiempo (snapshot SCN). Si un bloque tiene que ser modificado, los cambios se aplicarán a la versión actual del bloque. Sin embargo, la consulta de las filas a ser modificadas debe basarse en una versión del bloque consistente con el snapshot SCN. La reconstrucción temporal de una versión del bloque consistente con el snapshot SCN se denomina lectura consistente (consistent get ).


¿Por Qué fallan las lecturas consistentes?

Hay dos tipos de fallos en lecturas consistentes: fallo de rollback (rollback failure), y fallo de limpieza (cleanout failure).

Rollback Failure

Si después de que nuestra transacción o consulta haya comenzado se intenta leer un bloque que ha sido modificado por otra transacción confirmada posterior a nuestro snapshot SCN (es decir, nuestra transacción o consulta tiene un SCN menor al que aparece en dicho bloque), entonces se tiene que obtener una lectura consistente desde rollback para que nuestra operación en conjunto sea consistente, ya que no se pueden ver datos modificados y confirmados a mitad de consulta o a mitad de transacción (depende del nivel de aislamiento, como se explica más tarde en este artículo).

Sin embargo, si los cambios fueron realizados por una transacción discreta (ver Transacciones Discretas al final del artículo), no habrá información de rollback. Por lo que se producirá el error ORA-01555.

De la misma forma, se producirá el error si los bloques requeridos del segmento de rollback no están disponibles debido a que la extensión del segmento que los contenía ha sido desasignada por una operación de compresión (parámetro optimal del segmento de rollback) o reutilizada por otras transacciones ya existentes dentro del segmento o posteriores a la confirmada.

Para que se diera este último caso, información de rollback sobreescrita, se tendrían que haber utilizado al menos una vez desde el snapshot SCN todas las extensiones del segmento de rollback antes de sobreescribir los bloques de rollback necesarios. Por eso el mensaje de error Oracle sugiere que el segmento es demasiado pequeño (esto es como curiosidad).

Cleanout Failure

Cuando una transacción modifica filas de un bloque de datos, crea una entrada en el directorio de transacciones de la cabecera de dicho bloque, escribiendo su ID de transacción. Dicho ID contiene codificado el número de segmento de rollback asignado a la transacción, donde escribirá los valores antiguos. Esto quiere decir que dentro de cada bloque se indica dónde ir a leer los valores antiguos para consistencia en lectura.

Cuando la transacción haga commit, se incrementará el SCN del sistema y el nuevo valor será el commit SCN de esta transacción. Este commit SCN se guardará entonces en la entrada correspondiente de la tabla de transacciones, indicando que ya han sido confirmados los cambios. A partir de este momento, el rollback generado por esta transacción podrá ser sobreescrito por otras transacciones, así como su entrada en la tabla de transacciones del segmento de rollback.

Pero, para no afectar al rendimiento, Oracle no modificará todos los bloques involucrados para reflejar la confirmación. Esto se debe a que si la transacción afectaba a 1.000 bloques tendría que volver a visitarlos para poder modificarlos. Esta labor se deja para la siguiente transacción que visite el bloque, y es a lo que se denomina limpieza de bloque.

Por tanto, el directorio de transacciones que se guarda en la cabecera del bloque de datos, todavía reflejará una entrada para esa transacción como si estuviera actualizando el bloque y aún no se hubiera confirmado, y se mantienen los bloqueos a nivel de fila sobre las cabeceras de las filas afectadas.

Cuando el bloque sea leido por otra consulta o transacción ésta se encargará de hacer la limpieza de bloque, que consiste en comprobar si la transacción anterior se ha confirmado, y si es así se liberan los bloqueos sobre las filas y se guarda el commit SCN de la transacción en la entrada correspondiente del directorio de transacciones.

La nueva transacción cogerá el ID de la antigua que aparece en el directorio de transacciones, para comprobar si dicha transacción se ha confirmado o no. Extraerá el número de segmento de rollback codificado de dicho ID, y accederá a la entrada correspondiente en tabla de transacciones de la cabecera de dicho segmento.

Si en dicha entrada no se ha actualizado el commit SCN, significa que la antigua transacción aún no ha sido confirmada. Si, por el contrario, encuentra un valor para el commit SCN, la nueva transacción se encargará de hacer el block cleanout, liberando los bloqueos de las filas afectadas y eliminando del directorio la entrada de la transacción.

Si la transacción no ha sido confirmada o si fue confirmada después del snapshot SCN de la nueva transacción, hará falta leer de rollback como se explicó anteriormente. Pero si la transacción se confirmó antes del snapshot SCN de la nueva, no hará falta leer de rollback y la nueva transacción operará directamente sobre el bloque de datos.

Esto significa, que siempre se debe poder establecer la relación entre el snapshot SCN de la nueva transacción y el commit SCN de la transacción antigua.

La figura anterior representa el caso de encontrar la entrada de una transacción confirmada en la tabla de transacciones del segmento de rollback.

El problema surge si el bloque de cabecera del segmento de rollback ya no contiene la entrada para esa transacción, y por tanto el commit SCN de la antigua. Esto puede ocurrir ya que si este bloque es modificado con nuevas entradas de transacción y pueden ser sobreescritas las antiguas entradas.

En este caso, Oracle hará una lectura consistente recursiva del bloque de cabecera del segmento de rollback para obtener el commit SCN de la transacción. Es decir, Oracle intenta leer la información de rollback generada para la propia tabla de transacciones, de forma que obtenga la entrada con el commit SCN antes de haber sido sobreescrita.

Dicha información de rollback se almacena dentro del mismo segmento de rollback, y por tanto puede ser reutilizada o desasignada (durante compresiones) de la misma forma que el resto de la información de rollback.

Este caso es más improbable ya que tiene que coincidir que se reutilice la entrada de la cabecera (eso no es muy difícil, ya que las entradas de transacción se reutilizan cíclicamente) y que no esté disponible el rollback correspondiente a esta cabecera (se habrán reutilizado las extensiones del segmento de rollback varias veces, ya que las entradas de la tabla de transacciones se reutilizan cíclicamente y por tanto habrá pasado bastante tiempo). La siguiente figura muestra el caso de no encontrar la entrada de una transacción confirmada en la tabla de transacciones del segmento de rollback.

Hacer click en la imagen para verla ampliada


Recomendaciones para reducir el riesgo de error

Los casos más comunes que pueden presentar un rollback failure o cleanout failure:

  • Hacer fetch de un cursor abierto después de un commit, Oracle lo permite pero no es una operación ANSI standard. Se puede producir el error debido a que al abrir el cursor, éste adquiere el snapshot SCN de la consulta, y los commits irán generando nuevos commit SCNs.
  • Segmento de rollback corrupto: debido a que ciertos bloques no pueden ser leidos, no permitirá realizar la consistencia en lectura.
  • Segmentos de rollback muy pequeños: las entradas de rollback de una transacción confirmada se reutilizan demasiado rápido por nuevas transacciones.
  • Pocos segmentos de rollback: existen muchas transacciones usando el mismo segmento de rollback, por lo que existe mayor probabilidad de reutilización.

Para reducir la probabilidad de error frente a estos casos se proponen las siguientes recomendaciones:

  • No ejecutar transacciones discretas mientras se estén ejecutando consultas o transacciones que puedan verse perjudicadas, a menos que los dos conjuntos de datos sean totalmente independientes.
  • Planificar en el tiempo consultas y transacciones largas, de forma que las lecturas consistentes no necesiten consultar datos de rollback desde el snapshot SCN.
  • Codificar los procesos largos como módulos que se puedan ejecutar de nuevo independientemente de cualquier proceso anterior.
  • Comprimir todos los segmentos de rollback a su tamaño óptimo manualmente antes de ejecutar una consulta o transacción que pueda obtener el error de rollback debido a desasignación de extensiones durante su ejecución. Esto se puede hacer a través del siguiente bloque PL/SQL (se deben tener privilegios de ejecución del paquete sys.dbms_sql):

declare
id_c integer;
sentencia varchar2(100);
cursor nombres_sr is select r.segment_name
from sys.dba_rollback_segs r
where r.status ='ONLINE';
begin
id_c := sys.dbms_sql.open_cursor;
for reg in nombres_sr loop
sentencia := 'alter rollback segment ' ||reg.segment_name|| ' shrink';
sys.dbms_sql.parse(id_c, sentencia, sys.dbms_sql.native);
end loop;
sys.dbms_sql.close_cursor(id_c);
end;
/

Utilizar un tamaño optimo más grande en todos los segmentos de rollback para retrasar la reutilización de extensiones. Se puede saber aproximadamente cuánto tiempo queda antes de que se produzca el error, con el siguiente script que puede indicar el tiempo medio antes de que se reutilice una extensión de segmento de rollback.

Para Oracle 8.0.x ó 8.1.x:

column comentario format a53
column comentario heading "tiempo medio antes de reutilización de extensión ..."
column horas format 9999999 heading "en horas"
column minutos heading "en minutos"

select null comentario,
trunc(24* i.startup_time) / v.ciclos) horas,
trunc(1440*(sysdate- i.startup_time) / v.ciclos) minutos
from sys.v_$instance i,
(select max((r.writes + 24 * r.gets) / -- bytes usados
nvl(least(r.optsize, r.rssize), r.rssize) * -- tamaño de segmento
(r.extents - 1) / r.extents -- reducido en 1 extensión
) ciclos
from sys.v_$rollstat r
where r.status = 'ONLINE' ) v ;

Esta consulta muestra cuántas veces han sido reutilizadas extensiones desde el arranque de la instancia de BD e informan del tiempo medio existente antes de que una extensión sea reutilizada. Da una idea del tiempo que le queda a una transacción o consulta antes de que se produzca el error.

Este resultado no tiene en cuenta las transacciones discretas, ya que no generan rollback, ni el hecho de que los segmentos se pongan online/offline modificando las estadísticas consultadas.

  • Utilizar un tamaño de bloque Oracle de BD más grande, para que pueda haber más entradas de transacción en la tabla de transacciones del bloque de cabecera del segmento de rollback, retrasando de esta forma la reutilización de estas entradas.
  • Hacer commits menos frecuentes en las tareas que se ejecuten al mismo tiempo que las consultas o transacciones donde se pueden producir problemas, especialmente en procedimientos PL/SQL, de forma que se reduzca la reutilización de entradas de transacción en las tablas de transacciones (cada vez que se hace commit estamos comenzando una nueva transacción, luego incrementamos el número total de transacciones en el sistema).
  • Si es necesario, añadir segmentos de rollback extra para tener más entradas de transacción disponibles. Esta recomendación contradice la de usar un tamaño óptimo más grande, asumiendo que el espacio en disco disponible para segmentos de rollback es fijo. La elección de una estrategia u otra depende del riesgo de rollback failures con respecto a cleanout failures.

Representadas gráficamente:

Hacer click en la imagen para verla ampliada

Se observa que se han marcado dos de las soluciones propuestas - aumentar tamaño y número de segmentos de rollback - como complementarias. Vamos a explicar el por qué: · en el caso de un cleanout failure, aumentar el tamaño de los segmentos de rolback, ayudaría a que el rollback de la tabla de transacciones (para poder recuperar el commit SCN en caso de sobreescritura de la entrada) no sea sobreescrito tan rápidamente, ya que hay más espacio para las escrituras del resto de transacciones.

Sin embargo, resulta más adecuado aumentar el número de segmentos de rollback, ya que se consigue tener un número inferior de transacciones dentro de cada segmento de rollback, por lo que las entradas de transacción tardarán más en reutilizarse, resolviendo así el principal problema en el cleanout failure.

Por otro lado, aumentar el número de segmentos permite reducir una posible contención en el bloque de cabecera (tabla de transacciones) debido a que, como se ha indicado, existirán menos transacciones por segmento.

En el caso de un rollback failure, el problema se podría solucionar simplemente aumentando el tamaño de los segmentos de rollback para reducir el riesgo de una sobreescritura de la información requerida para la consistencia en lectura.

Las ventajas de aumentar el número de segmentos de rollback son una reducción de contención en el bloque de cabecera como se ha explicado anteriormente, y menor probabilidad de sobreescritura debido a una mejor distribución de transacciones por segmentos de rollback. Sin embargo, no evitaría el hecho de que una transacción larga reutilice el rollback de una transacción confirmada necesario para la consistencia en lectura, ya que aunque tengamos más segmentos, siguen siendo pequeños y habrá gran cantidad de sobreescrituras.

Como solución de compromiso, se puede hallar un equilibrio entre estas dos soluciones, obteniendo de esta forma las ventajas de ambas.


¿Qué hacer si todo falla?

Para ciertas consultas y transacciones no es necesario hacer todo lo indicado anteriormente. Sólo se necesita prevenir la liberación o reutilización de extensiones necesarias para consistencia en lectura.

Un método sencillo es asegurarse de que haya un único segmento de rollback grande online en el momento del snapshot SCN, y forzar a que la consulta o transacción utilice ese segmento de rollback. Esto asegura que no se liberarán/reutilizarán extensiones hasta que finalice la consulta o transacción, ya que considera que todas las extensiones afectadas por la operación tienen una transacción activa y por tanto no puede liberarlas ni reutilizarlas.

Una variación de esta solución es dejar en cada segmento de rollback online una transacción sin confirmar, aunque aumenta el riesgo de quedarse sin espacio en los tablespaces donde se hayan creado los segmentos de rollback (esto es fácil de controlar).

A continuación se incluyen una serie de scripts para aplicar esta técnica en un sistema Unix:

El primer script a ejecutar crea una tabla en un hash cluster dentro del esquema del usuario System que se usará en los siguientes scripts para implementar y memorizar la protección de los segmentos de rollback frente a la liberación/reutilización de extensiones.

create cluster system.prevent_1555 (segment_name varchar2(30)) hashkeys 29;

create table system.protected_rollback_seg
(
segment_name varchar2(30),
protection_expires date
) cluster system.prevent_1555(segment_name);

Este es el script principal denominado prevent_1555.sql, se invoca para asegurar la protección frente al error ORA-01555 durante un número determinado de segundos. Genera un script unix que al ser ejecutado invoca a protect_rbs.sql, que se comentará posteriormente, para cada segmento de rollback online de la BD.

La forma de ejecutarlo es:

sqlplus -s / @prevent_1555
rbs_protectors=$(sh prevent_1555.sh)

kill $rbs_protectors

y su contenido es:

set define :
set verify off
set recsep off
set heading off
set feedback off
set termout off
set trimspool on

spool prevent_1555.sh
prompt rm -f prevent_1555.sh
select
'sqlplus / @protect_rbs ' || segment_name || ' :1 > /dev/null & echo $!'
from
sys.dba_rollback_segs
where
status = 'ONLINE' and
segment_name != 'SYSTEM' ;
spool off
exit

El script protect_rbs.sql que se incluye a continuación es ejecutado automáticamente para cada segmento de rollback online por el script unix prevent_1555.sh generado en el punto anterior. Se encarga de comprimir el segmento de rollback especificado para reducir el riesgo de quedarnos sin espacio en los tablespaces de rollback. Después memoriza su protección en la tabla de control, antes de dejar la transacción sin confirmar pendiente durante el número de segundos especificado. La invocación a este script tiene la siguiente sintaxis (no hay que ejecutarlo manualmente):

sqlplus -s / @protect_rbs &

alter rollback segment &1 shrink;
delete from system.protected_rollback_seg
where segment_name = '&1' and protection_expires < sysdate;
insert into system.protected_rollback_seg values ('&1', sysdate + &2/86400);
commit;
set transaction use rollback segment &1;
delete from system.protected_rollback_seg
where segment_name = '&1' and protection_expires <= sysdate + &2/86400;
execute sys.dbms_lock.sleep(&2);
commit;
exit

El script protected_rollback_segs.sql que se incluye a continuación monitoriza el estado de protección de los segmentos de rollback cuando han sido protegidos mediante el script prevent_1555.sql:

select substr(d.segment_name, 1, 14) "SEGMENT NAME", v.extents, v.rssize bytes,
v.optsize "OPTIMAL", v.xacts transactions,
substr(to_char(p.protection_expires,'HH24:MI:SS DD/MM/YY'),1,18)"Protegido Hasta"
from sys.dba_rollback_segs d, sys.v_$rollstat v, system.protected_rbs p
where d.segment_id = v.usn and d.segment_name = p.segment_name (+)
and sysdate < p.protection_expires (+) ;


¿Cómo conocer la causa real del problema?

Para saber si el error se está produciendo por rollback failure o por cleanout failure (número de entradas de la tabla de transacciones) se puede incluir el siguiente evento en el fichero init.ora:

event = "1555 trace name processstate forever, level 10"

que hará un volcado del estado de proceso para cada proceso en el que se produzca el error. Este volcado muestra qué bloque se estaba buscando para la lectura consistente. Si se trata del bloque de cabecera de un segmento de rollback entonces hay que investigar.

El número de entradas de transacción que puede haber en la tabla de transacciones del bloque de cabecera está en función del tamaño de bloque Oracle. La única forma de tener más entradas disponibles es añadir más segmentos de rollback o tener un tamaño de bloque Oracle más grande.

Por otro lado, muchos autores recomiendan crear diferentes tamaños de segmentos de rollback evaluando el tipo de transacciones según el volumen de escrituras que hacen en rollback y teniendo en cuenta el número de transacciones simultáneas de cada tipo: segmentos de rollback pequeños para las transacciones con pocas escrituras, ... Crear segmentos pequeños no beneficia en nada, salvo que no desperdiciamos espacio, pero esta reutilización de espacio hace más posible que se produzca el error ORA-01555.


Los tres niveles de aislamiento de transacciones

Oracle suministra tres niveles de aislamiento para consistencia de datos entre transacciones:

· Read commited: es el nivel por defecto. Cada consulta ejecutada por una transacción sólo ve los datos que fueron confirmados antes de que comenzara la consulta (no la transacción), por lo que una consulta de una transacción nunca verá datos de otras transacciones sin confirmar. Problema: una transacción que ejecute varias veces la misma consulta puede obtener diferentes resultados en cada una de las ejecuciones. Para indicar que una transacción comience con este tipo de aislamiento: o no indicar nada, o utilizar como primer sentencia de la transacción:

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

· Transacciones serializables: ven sólo aquellos cambios que fueron confirmados en el momento en que comenzó la transacción, además de los cambios que realice la propia transacción durante su ejecución. Con este nivel se evita el problema de dos ejecuciones de la misma consulta devolviendo diferentes resultados que se daba en read-commited.

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

· Read-Only: como las serializables pero no permiten sentencias insert/update/delete como parte de la transacción.

SET TRANSACTION ISOLATION LEVEL READ ONLY;

El error snapshot too old se puede dar en los tres niveles, pero es más probable en los dos últimos ya que se fuerza a mantener una mayor cantidad de información en rollback sin ser sobreescrita. Por tanto, se debería fijar el nivel de aislamiento al más adecuado para cada caso.

Por ejemplo, Oracle Reports, en el trigger Before Report incluye la sentencia set transaction read only, con lo que solicita consistencia en lectura para construir absolutamente todo el report. Esto no es necesario en todos los reports que contienen varias consultas, por lo que habrá que analizar si se puede obtener el report con un nivel de aislamiento menor, de manera que se disminuya la posibilidad de error.


Transacciones discretas

Cuando una transacción realiza una operación de actualización de datos(DML), Oracle además de bloquear las filas involucradas en la actualización, escribe los valores antiguos en rollback, modifica los bloques de datos original con los nuevos valores, y escribe en lo ficheros de redo log una entrada para poder deshacer la operación en caso de caída de la BD durante el siguiente arranque de la instancia de BD.

Oracle provee un mecanismo denominado transacciones discretas que difiere las escrituras a bloques de datos y a redo log hasta que la transacción hace commit. Tampoco se escribe a rollback ya que no se están realizando los cambios "realmente" sobre los bloques de datos originales.

Por tanto, pueden mejorar el rendimiento para ciertas transacciones pequeñas, pero pueden tener varios problemas, entre ellos el error "snapshot too old" en situaciones como la siguiente:

El caso general es que existen consultas que tratan de leer los bloques modificados mientras hay transacciones discretas en curso:

Lanzamos una consulta larga sobre una tabla que está siendo modificada por una transacción discreta. Si la transacción hace commit después de que la consulta haya comenzado a ejecutarse pero antes de que finalice completamente su ejecución, puede ocurrir que cuando la consulta va a recuperar una fila Oracle detecta que ésta ha sido modificada desde que comenzó la consulta e intenta ir a buscar el valor antiguo de la fila a rollback. Como las transacciones discretas no generan entradas de rollback es como si el valor en rollback se hubiera sobreescrito, produciéndose el problema snapshot too old.

Nota: para realizar una transacción discreta:

Dbms_transaction.begin_discrete_transaction;
[...] operaciones DML de actualización [...]
commit;


Fuentes documentales

  • Manuales de referencia de Oracle: Concepts, Administrator's Guide

  • Parte del código de este artículo así como información sobre el ORA-01555 se ha obtenido de diversos documentos publicados en el servicio Metalink:
    http://metalink.oracle.com



    Sobre el autor


    Patricia Peña ha sido profesora de postgrado en la Universidad de Deusto y ha impartido numerosos cursos especializados en administración de Bases de Datos Oracle. En la actualidad dirige el Centro de Formación de Tecsidel. Para más información, contactar con patricia.penya@mad.tecsidel.es



    Documentos relacionados






    Otros documentos del mismo autor




    © Copyright 2002 Patricia Peña Cobo.
    © Copyright 2002 REDcientífica.
    Todos los derechos reservados.


    [Evaluar este artículo]








  •               Misión de REDcientífica              Condiciones de publicación              E-mail de contacto



      Bookmark and Share