- SQL
- PL/SQL
- DBA
- Developer / Forms
- Developer / Reports
- Developer / Graphics
- Data-Warehouse

 
 
 

 
> Tutorials DBA
 

ORA-01555 snapshot too old
di Emanuela Marottoli

L’errore "ORA-01555 snapshot too old", che causa il fallimento delle transazioni è diventato un incubo per gli sviluppatori e i DBA.
Accade solitamente quando query e processi durano troppo a lungo, il che vuol dire che si possono perdere molte ore in attesa che il processo termini per poi essere bloccati da questo errore.

E’ molto difficile riuscire a ricreare l’errore, e la causa segnalata dal manuale di Oracle dei messaggi di errore è che il segmento di rollback è troppo piccolo. Tuttavia nella maggior parte dei casi vi accorgerete che c’è abbastanza spazio nel rollback della tablespace come pure nel segmento di rollback occupato dalla transazione.

Tre sono le situazioni che possono causare l’errore ORA-01555:

  • Una base di dati con un numero insufficiente di segmenti di rollback
  • Una frammentazione del segmento di rollback che impedisce l’esecuzione della query
  • Si possono incrociare delle FETCH mentre i cursori sono aperti

È possibile evitare questo errore assegnando i segmenti di rollback e configurando i parametri adeguati.
Prima di esaminare a fondo questo problema, sarà necessario spiegare prima di tutto cosa sono i segmenti di rollback. I segmenti di rollback sono coinvolti in ogni transazione che si presenta all'interno d'una base dati. Poiché gestiscono la capacità della base di dati di maneggiare le transazioni, svolgono un ruolo chiave nel buon funzionamento della base dati stessa.
I segmenti di rollback catturano ‘l' immagine’ dei dati come erano prima dell' inizio della transazione infatti le query effettuate durante una transazione restituiranno i dati ‘catturati’ dal rollback. Il numero e la grandezza dei segmenti di rollback sono specificati dal DBA durante la creazione della base dati. Le informazioni sulle condizione dei segmenti di rollback sono contenuti nella vista DBA_ROLLBACK_SEGS.

Un segmento di rollback consiste in una serie di blocchi attigui chiamati extents. In una base dati ideale, ogni transazione dovrebbe essere eseguita all'interno di una singola extent. Tuttavia, ciò accade raramente. Quando una transazione non ha più spazio sufficiente per essere eseguita all’interno di un extent, il segmento di rollback cerca un altro extent in cui poter continuare a scrivere. Il segmento usa l’ extents in maniera ordinata e circolare, spostandosi da un extent all’altro in maniera sequenziale dopo che l’ extent precedente è stato pienamente occupato come si trattasse di un record. La parte iniziale del record è la head del segmento di rollback. La coda è il tail.
È tuttavia importante assicurarsi che i diversi segmenti di rollback siano abbastanza grandi per maneggiare il loro carico di transazione.

La documentazione ORACLE suggerisce alcune regole utili a riguardo dei segmenti di rollback:

Una transazione può usare soltanto un segmento di rollback per memorizzare tutto il relativo record.
Le transazioni multiple possono scrivere nello stesso extent.
La head del segmento di rollback non entra mai in un extet di rollback attualmente occupato dal tail.
Se la head non può usare l’extent seguente, assegna un altro l’extent e lo inserisce nel blocco

Da questi principi si può dedurre che il tempo di transazione così come il formato della transazione è importante. Per esempio, una transazione che modifica soltanto un byte ma necessita di un periodo di tempo abbastanza lungo prima che venga terminato potrebbe indurre un segmento di rollback a crescere senza che sia effettivamente necessario.

La grandezza necessaria per un segmento di rollback dipende direttamente dalle transazioni che avvengono nella base dati, se queste sono rare o frequenti.
Il numero dei segmenti di rollback sono necessari per impedire il conflitto fra i processi e può essere determinato con l' uso della vista di V$WAITSTAT. I ‘wait’ di tale vista sono indicativi del conflitto. La seguente query di V$WAITSTAT visualizza il numero di ‘wait’ dall’inizio dell’istanza.

SELECT Class, Count
FROM V$WAITSTAT
WHERE Class LIKE '%undo%';

Qualsiasi valore diverso da zero nella colonna count indica l’esistenza di un conflitto nell’ intestazione del segmento di rollback.
Per sapere la grandezza ed il numero di rollback segments necessari alla base dati, è sufficiente effettuare un test. È possibile cominciare con i piccoli segmenti di rollback e fare in modo che l’applicazione li forzi ad estendersi. Il formato massimo che tutto il segmento di rollback raggiunge durante il test è il formato necessario da utilizzare. Se il più grande formato richiede meno di 10 extent, o più di 30, sarebbe necessario abbassare o aumentare la grandezza dell’extent e ripete il test. Per le grandi transazioni è possibile creare i segmenti separati di rollback.
Per settare la grandezza dell’ extent del rollback segment è raccomandabile utilizzare lo stesso valore per ogni extent ed assegnare al rollback segment una grandezza pari a un multiplo della grandezza dell’extent.

I segmenti di rollback assegnano dinamicamente lo spazio una volta richiesti e cancellano l'assegnazione dello spazio quando non sono più necessari (se utilizzati gli adeguati paramentri). Quanti meno extent ha un segmento di rollback, tanto più frammentato potrebbe essere lo spazio da esso occupato. Per esempio, consideriamo un segmento di rollback di 200MB suddiviso in due extents di 100MB ognuna. Se questo segmento dovesse richiedere dello spazio supplementare, si creerebbe un altro extent di 100MB. Ciò farebbe aumentare la grandezza del segmento di rollback del 50 per cento senza che tutto questo spazio in più sia realmente necessario. Al contrario, se il segmento di rollback fosse composto da 20 extent di 10MB, tutto lo spazio aggiunto sarebbe di soli 10MB. Quando un segmento di rollback è costituito da 20 o più extent, ogni singolo cambiamento nel numero di extent non modificherà la grandezza totale del segmento di rollback più del 5 per cento.

Detto questo, aumentare il numero di extent oltre i 20 suggeriti renderà la ripartizione dello spazio ancora più regolare. Tuttavia, aumentare e diminuire le extent non è un operazione senza costi. La base dati avvertirà la ‘degradazione’ di prestazioni quando ad un segmento di rollback è costantemente assegnato e/o cancellato l'assegnazione di extent.

Una query non vede mai i cambiamenti fatti ai dati dalle transazioni che committano durante il corso dell'esecuzione della query. Oracle identifica unicamente dei punti nel tempo con un insieme di numeri chiamati System Change Numbers (numeri di cambiamento del sistema). Si pensi allo SCN come la condizione della base dati in un determinato momento. Quando una query inizia la sua esecuzione, oracle gli assegna uno SCN. La query può vedere soltanto lo snapshot (la fotografia) dei record così come sono nel momento in cui gli e stato assegnato l’ SCN. Ogni volta che una transazione effettua una modifica dei dati viene effettuato uno snapshot del record che verra modificato, in un segmento di rollback a cui verrà assegnato un proprio indirizzo
Se ci sono dati non committati da altre transazioni, oppure ci sono modifiche in corso con un SCN più-recente, allora i dati saranno ricostruiti usando lo snapshot salvato dai segmenti di rollback. Un segmento di rollback conserva lo snapshot dei dati cambiati finchè la transazione è ancora attiva (cioè non è stato eseguito un rollback o una commit). Una volta che una transazione è committata, la base dati la contrassegna con uno SCN corrente e lo spazio usato dallo snapshot diventa riutilizzabile. Di conseguenza, un errore Ora-01555 accadrà se la query sta cercando uno snapshot che è così vecchio che le informazioni di segmento di rollback non potrebbero essere trovate.

Se la basedati ha molte transazioni che cambiano i dati e committano molto spesso, come in un ambiente di elaborazione di transazioni in linea (OLTP), la probabilità di riutilizzare lo spazio usato da una transazione è più alto. Una query in esecuzione da molto tempo allora non può creare lo snapshot. I più grandi segmenti di rollback in questo caso ridurranno la probabilità di riutilizzazione delle scanalature committate dalle transazione.
In questo caso dovreste studiare la possibilità di aggiungere più segmenti di rollback e di aumentare la loro grandezza. Il formato ed il numero dei segmenti di rollback dipendono dalle richieste della vostra applicazione e del numero di utenti connessi contemporaneamente.
Nella clausola di rollback, c’è un parametro chiamato OPTIMAL che specifica il segmento ottimale di rollback in byte. Quando questo è settato, la basedati proverà a mantenere al segmento il formato specificato. Se è necessario dello spazio supplementare oltre il formato ottimale, il segmento di rollback si espanderà oltre il formato ottimale per accomodare la transazione corrente, ma quindi cancellerà l'assegnazione dell’extent per ritornare di nuovo al formato specificato. Quando il parametro OPTIMAL è troppo basso, potrebbe causare l’ errore Ora-01555.
Per fornire le prestazioni migliori, bisognerebbe settare tutti i segmenti di rollback ad un formato adeguato ad ogni singola transazione. In pratica però questo potrebbe essere impossibile, per esempio, se la transazione è 500MB e il numero di segmenti di rollback è 30.
La grandezza ottimale dei segmenti dovrebbe essere tale che il 90 per cento delle transazioni non richiedano estensioni dei segmenti. In più, la tablespace di rollback dovrebbe essere abbastanza grande in modo che quando tutti i segmenti di rollback sono al valore ottimale, ci sia abbondanza di spazio affinchè si possano estendere quando diventa necessario. Per esempio, se i segmenti sono regolati con un valore ottimale di 50MB e sapete che c’ è una transazione particolare che viene eseguita raramente, ma richiede 1GB, la tablespace di rollback dovrebbe avere almeno 950MB liberi quando tutti i segmenti in quella tablespace sono al formato ottimale. Poiché non è possibile avere tutti i segmenti alla grandezza ottimale o che la transazione sia l’unica ad utilizzare il segmento di rollback, si dovrebbe avere almeno dal 30 al 40 per cento di spazio disponibile in più .

Se invece un segmento di rollback è corrotto e non può essere letto, sarà necessario droppare e ricreare il segmento di rollback.
È possibile droppare un segmento di rollback soltanto se è offline. Per determinare se un segmento di rollback è offline, è necessario interrogare la vista del data dictionary
DBA_ROLLBACK_SEGS. I segmenti di rollback offline hanno il valore dello STATUS ad AVAILABLE, mentre i segmenti offline hanno il valore di STATUS ad IN_USE.
Per portare offline dei segmenti di rillback basta eseguire il seguente comando:

ALTER ROLLBACK SEGMENT ‘nome rallback’ OFFLINE;
DROP ROLLBACK SEGMENT ‘nome rallback’;

Quando viene generato un segmento di rollback, è inizialmente offline, e per portarlo on-line basta eseguire il seguente comando in cui viene specificata la tablespace altrimenti Oracle lo genererà nalla tablespace di sistema

CREATE ROLLBACK SEGMENT ‘nome rallback’ TABLESPACE ‘nome tablespace’;
ALTER ROLLBACK SEGMENT ‘nome rallback’ ONLINE;

Per aggiornare, cancellare o creare un segmento di rollback è necessario avere i privilegi relativi (ALTER ROLLBACK SEGMENT, DROP ROLLBACK SEGMENT, and CREATE ROLLBACK SEGMENT) .