Comments
Description
Transcript
Indietro nel tempo con Flashback Query
PROGRAMMING Database Nella versione 9i del database più diffuso al mondo sono state aggiunte molte nuove funzionalità, una di queste consente di visualizzare i dati com’erano in un determinato istante del passato Indietro nel tempo con Flashback Query Oracle9i S ono le dieci di sera, state impazzendo sul database di un cliente perché c’è qualcosa che non vi torna nei dati. Dopo avere fatto decine di select, pregato in molti modi il Santo protettore dei programmatori e pianto lacrime amare, vi giunge l’illuminazione: <<Eureka! Ecco i record di troppo!>>. Pensate subito al programma, o all’utente, che sbagliando ha inserito quei dati. OK, niente panico, cancello questi record e sono a cavallo! Il comando da eseguire si scrive in pochi secondi: Delete from tabella Where condizione; Commit; «A posto! Controlliamo, per sicurezza… ma… che succede… perché non trovo più…? NO! HO CANCELLATO LE RIGHE SBAGLIATE!». Dite la verità, se lavorate su database da un po’ di tempo sicuramente vi è capitato. Dato il comando di Commit, il danno è fatto ed irreparabile. Bisogna recuperare il backup (se è disponibile) e questo comporta comunicare l’errore al cliente e, soprattutto, al proprio capo. Problemi in vista! Il database è Oracle 9i? Ok, non ci sono problemi, c’è modo per recuperare subito le righe cancellate mediante una flashback query. In quest’articolo vedremo cos’è e come si utilizza il package DBMS_FLASHBACK. In generale… La logica è piuttosto semplice: i dati modificati vengono conservati in un apposito tablespace, detto di Massimo Ruocchio [email protected] È laureato in matematica ed è certificato Oracle Application Developer. Si occupa di analisi, progettazione e sviluppo di applicazioni software. UNDO Tablespace, anziché nei classici Rollback Segment. Si stabilisce un ammontare di tempo (chiamiamolo periodo di conservazione) durante il quale il DBMS deve conservare i dati modificati in questo tablespace. Scaduto il periodo di conservazione, i dati potranno essere sovrascritti. In qualunque momento all’interno del periodo di conservazione, è possibile leggere i dati com’erano in un istante precedente. I dati vecchi possono, ovviamente, essere reinseriti nelle tabelle attuali in modo da ripristinare, a tutti gli effetti, la situazione antecedente all’istruzione da annullare. La lettura dei dati dal tablespace di UNDO è effettuata mediante il package DBMS_FLASHBACK che vedremo nel dettaglio più avanti. Se il periodo di conservazione è scaduto ma i dati non sono stati sovrascritti nel tablespace di UNDO, allora è comunque possibile effettuare la lettura dei vecchi dati. Ma come si individua l’istante temporale a cui si intende ritornare? In due modi: mediante un system change number oppure mediante un timestamp. Un system change number non è altro che un numero attribuito automaticamente da Oracle ad ogni modifica occorsa al sistema. Nel Listato 1 c’è un esempio 57 CP 115 PROGRAMMING Database Il compito del DBA LISTATO 1 Esempio di assegnazione dei System Change Number SQL*Plus: Release 9.0.1.0.1 - Production on Mar Mar 19 11:45:19 2002 (c) Copyright 2001 Oracle Corporation. All rights reserved. La prima cosa da fare è creare il tablespace di UNDO. L’istruzione è semplice: Create UNDO tablespace nome Datafile percorso SIZE Dimensione; Connesso a: Oracle9i Personal Edition Release 9.0.1.1.1 - Production JServer Release 9.0.1.1.1 - Production A questo punto bisogna impostare tre parametri di inizializzazione: SQL> Select * from pippo; PLUTO ---------1 2 3 4 5 SQL> declare 2 xscn number; 3 begin 4 5 for i in 1..5 loop 6 select dbms_flashback.get_system_change_number 7 into xscn 8 from dual; 9 dbms_output.put(‘OLD SCN=’||xscn); 10 delete pippo where rownum=1; 11 12 commit; 13 14 select dbms_flashback.get_system_change_number 15 into xscn 16 from dual; 17 dbms_output.put_line(‘ - NEW SCN=’||xscn); 18 19 end loop; 20 21 end; 22 / OLD SCN=209928 - NEW SCN=209930 OLD SCN=209930 - NEW SCN=209931 OLD SCN=209931 - NEW SCN=209932 OLD SCN=209932 - NEW SCN=209933 OLD SCN=209933 - NEW SCN=209935 Procedura PL/SQL completata correttamente. UNDO_MANAGEMENT deve essere impostato ad AUTO per consentire la gestione automatica del tablespace di UNDO; UNDO_TABLESPACE deve essere valorizzato con il nome del tablespace di UNDO creato; UNDO_RETENTION deve essere valorizzato con il numero di secondi che definiscono il periodo di conservazione, per default vale 900 (15 minuti). Dopo avere impostato il parametro UNDO_ MANAGEMENT bisogna riavviare il Database, perché il parametro viene letto solo nella fase di start-up. Infine bisogna dare all’utente che intende utilizzare il package DBMS_FLASHBACK il permesso di farlo, quindi connessi con l’utente SYS bisogna dare il comando GRANT EXECUTE ON DBMS_FLASHBACK TO nomeutente; A questo punto il compito del DBA è finito (non c’è voluto molto, in verità) e comincia il compito dello sviluppatore. Per di più nell’installazione standard di Oracle9i i passi che abbiamo elencato (tranne la concessione della GRANT) vengono eseguiti automaticamente. Nel prossimo paragrafo descriviamo nel dettaglio il package DBMS_FLASHBACK. SQL> Il package DBMS_FLASHBACK 58 CP 115 per capire il funzionamento del system change number. La tabella PIPPO contiene cinque record. Lo script effettua la delete di una riga alla volta e, per ogni cancellazione, mostra il system change number prima e dopo l’operazione. Come si vede, il system change number cambia per ogni istruzione di delete eseguita. È possibile tornare ad uno stato precedente del database passando un timestamp (cioè una data munita di ore, minuti, secondi e frazioni di secondo), ma c’è un problema di precisione di cui parleremo più avanti. Ovviamente, affinché il package DBMS_ FLASHBACK possa essere utilizzato, il database deve essere opportunamente parametrizzato. L’attività di impostazione e parametrizzazione tocca al DBA e sarà discussa nel prossimo paragrafo. Il package è costituito dalle seguenti procedure e funzioni: Procedure enable_at_time(query_time in TIMESTAMP); Procedure enable_at_system_change_number (query_scn in NUMBER); Procedure disable; Function get_system_change_number return NUMBER; La funzione GET_SYSTEM_CHANGE_NUMBER ritorna il system change number corrente. L’abbiamo vista utilizzata nel Listato 1. Per far tornare il sistema ad una situazione antecedente bisogna utilizzare una delle procedure ENABLE_AT, passando un istante (timestamp) oppure un system change number. Mediante la procedura DISABLE si fa ritornare il sistema allo stato corrente. Dopo una ENABLE_AT, e prima di una DISABLE, non è possibile modificare i dati né effettuare un’ulteriore ENABLE_AT. Si tratta a tutti gli effetti di una sessione di sola lettura dei dati così com’erano in un momento precedente. Facciamo qualche esempio. Un po’ di pratica LISTATO 2 Ripristino dei dati SQL*Plus: Release 9.0.1.0.1 - Production on Mar Mar 19 12:42:49 2002 (c) Copyright 2001 Oracle Corporation. All rights reserved. Connesso a: Oracle9i Personal Edition Release 9.0.1.1.1 Production JServer Release 9.0.1.1.1 - Production SQL> select * from pippo; Nessuna riga selezionata Abbiamo cancellato queste benedette righe e dobbiamo reinserirle. Abbiamo imparato a leggere i dati come erano ad un certo istante, ma abbiamo visto che durante una sessione di FLASHBACK non è possibile effettuare inserimenti. Vediamo come fare per ripristinare i dati. Dal Listato 1 vediamo che, prima della prima cancellazione dalla tabella PIPPO, il system change number era 209928. Nel Listato 2 ripristiniamo la tabella come era in quel momento. Si può tornare ad un istante oppure ad un System Change Number Dichiariamo un cursore che prende i dati dalla tabella PIPPO e lo apriamo all’interno di una sessione FLASHBACK relativa al system change number desiderato. Prima di effettuare gli inserimenti in tabella chiudiamo la sessione di FLASHBACK, tanto ormai i vecchi dati sono stati caricati in memoria. Scorriamo il cursore dei vecchi dati ed inseriamo nella tabella attuale. Se proprio non riusciamo a fare a meno dei cicli For, possiamo fare come indicato nel Listato 3. Abbiamo dichiarato una PL/SQL Table chiamata TN e basata sul tipo TAB_N (che è un vettore di variabili numeriche). All’interno della sessione FLASHBACK abbiamo caricato il vettore e, dopo essere tornati alla situazione attuale, lo abbiamo scorso per ripopolare la tabella. Il risultato è lo stesso. Il problema dei Timestamp Cos’è un timestamp? Timestamp(N) è un nuovo tipo di dato presente in Oracle9i che aggiunge alla data classica le frazioni di secondo. N indica il numero di cifre decimali dei secondi e può valere da 0 a 9, dunque la precisione del timestamp può arrivare fino al miliardesimo di secondo. Per consentirci di gestire SQL> Declare 2 Cursor PIPPO_OLD is 3 select * from pippo; 4 N Number; 5 Begin 6 DBMS_FLASHBACK.ENABLE_AT_SYSTEM_ CHANGE_NUMBER(209928); 7 OPEN PIPPO_OLD; 8 DBMS_FLASHBACK.DISABLE; 9 loop 10 FETCH PIPPO_OLD INTO N; 11 Exit When PIPPO_OLD%NOTFOUND; 12 Insert into pippo values(N); 13 End loop; 14 Commit; 15 End; 16 / Procedura PL/SQL completata correttamente. SQL> Select * from pippo; PLUTO ---------1 2 3 4 5 SQL> meglio i timestamp, Oracle ha fornito una funzione di conversione (TO_TIMESTAMP) ed una funzione che restituisce il timestamp di sistema (SYSTIMESTAMP). Per intuito, quando si sente parlare di “tornare indietro ad una situazione precedente”, si pensa ad un particolare istante. È quindi ovvio che ci debba essere la possibilità di vedere il sistema com’era, ad esempio, il giorno 18 di Marzo 2002 alle ore 10, 45 minuti, 23 secondi e 275 millesimi (a patto che questa data ricada nel periodo di conservazione). Il package DBMS_FLASHBACK mette a disposizione la funzione ENABLE_AT_TIME che, preso in input un timestamp, cerca il system change number corrispondente ed effettua una chiamata alla procedura ENABLE_AT_SYSTEM_CHANGE_NUMBER. C’è, però, un problema: per associare il timestamp al system change number, Oracle conserva automaticamente ogni cinque minuti il timestamp ed il system change number correnti. Quando l’utente richiede di tor- 59 CP 115 PROGRAMMING Database LISTATO 3 Ripristino dei dati utilizzando due cicli FOR SQL> select * from pippo; Nessuna riga selezionata SQL> Declare 2 Cursor PIPPO_OLD is 3 select * from pippo; 4 type TAB_N is table of Number index by binary_integer; 5 TN TAB_N; 6 i number := 1; 7 Begin 8 DBMS_FLASHBACK.ENABLE_AT_SYSTEM_ CHANGE_NUMBER(209928); 9 10 For rec in PIPPO_OLD loop 11 TN(i):= rec.pluto; 12 i := i + 1; 13 End loop; 14 15 DBMS_FLASHBACK.DISABLE; 16 17 For i in 1..TN.count loop 18 Insert into pippo values(TN(i)); 19 End loop; 20 21 Commit; 22 23 End; 24 / In due minuti e mezzo su un Database può succedere di tutto, quindi i dati potrebbero essere molto diversi da quelli che ci aspettiamo. Come risolvere questo problema? Si può creare una tabella applicativa che conserva le coppie (timestamp, system change number) ad una frequenza superiore ad una volta ogni cinque minuti oppure ad ogni modifica delle tabelle critiche. La struttura della tabella potrebbe essere la seguente create table TAB_SCN_TIME (TSTAMP Timestamp(9), SYSTEMCN Number); Poi basterebbe scrivere una semplice procedura del tipo: create or replace procedure TORNA_ALLE (Istante in TIMESTAMP) is xSCN number; Begin DBMS_FLASHBACK.DISABLE; Select SYSTEMCN into xSCN from TAB_SCN_TIME where TSTAMP = ( Select Max(TSTAMP) From TAB_SCN_TIME Where TSTAMP <= Istante); Procedura PL/SQL completata correttamente. SQL> Select * from pippo; DBMS_FLASHBACK.ENABLE_AT_ SYSTEM_CHANGE_NUMBER(xSCN); PLUTO ---------1 2 3 4 5 Exception When no_data_found then Null; End; / SQL> nare ad un certo istante, Oracle determina il system change number registrato più prossimo al timestamp richiesto, ma questo system change number potrebbe essere relativo ad una situazione dati che si era verificata due minuti e mezzo prima o dopo rispetto all’istante che avevamo richiesto. che fa all’incirca le stesse operazioni della procedura ENABLE_AT_TIME associando, però, all’istante richiesto dall’utente, un system change number più significativo. Nella procedura precedente abbiamo inserito una DISABLE prima di ogni ENABLE per evitare l’errore ORA-08184 che corrisponde al tentativo di riabili- TABELLA 1 Errori collegati al Package DMBS_FLASHBACK 60 CP 115 Errore Descrizione ORA-8180 Si è cercato di tornare indietro oltre il periodo di conservazione ed i dati sono stati già sovrascritti nel tablespace di UNDO. ORA-8181 Si è specificato un system change number non valido. ORA-8182 Quando si è in modalità Flashback non è possibile eseguire istruzioni che modificano i dati o le strutture dati (DML e DDL). ORA-8183 Prima di entrare in modalità Flashback bisogna chiudere la transazione facendo Commit oppure Rollback. ORA-8184 Quando si è in modalità Flashback non è possibile aprire una nuova sessione con ENABLE prima di avere chiuso la precedente con DISABLE. ORA-8185 L’utente SYS non è abilitato a lavorare in modalità Flashback. tare la modalità Flashback mentre si è già in modalità Flashback. Gli altri errori collegati all’utilizzo del package DBMS_FLASHBACK sono elencati in Tabella 1. Per quanto visto in questo paragrafo possiamo affermare che conviene fare riferimento, laddove possibile, ai system change number invece che ai timestamp. Conclusioni La possibilità di vedere i dati com’erano in un istante del passato, e poi di poterli riutilizzare, stuzzica molto la fantasia dello sviluppatore. Non solo per riparare agli inevitabili errori. Ad esempio si potrebbe aggiungere, ad una funzione che visualizza delle statistiche su dati che cambiano velocemente, la possibilità di vedere com’era la situazione in un istante precedente scelto dall’utente (ovviamente all’interno del periodo di conservazione). Molti altri utilizzi possono essere trovati per il package DBMS_FLASHBACK, ma bisogna tenere conto delle limitazioni e della logica dell’oggetto. Meglio, allora, scrivere codice ragionando in termini di system change number anziché di timestamp. Se in un certo istante occorre una modifica strutturale di una tabella, anche solo l’allargamento di un campo, i dati di quella tabella precedenti a tale modifica non saranno più recuperabili, quindi conta molto anche la stabilità del database. DBMS_FLASHBACK ed il datatype TIMESTAMP sono solo due delle modifiche migliorative apportate ad Oracle9i. Per maggiori informazioni su questi strumenti si possono consultare le risorse indicate in Bibliografia e nei Riferimenti. Altre novità introdotte nell’ultima versione di Oracle saranno trattate nei prossimi numeri di Computer Programming. BIBLIOGRAFIA [1] Oracle – “Oracle9i Flashback Query”, Oracle Corp., 2001 [2] Oracle – “Oracle9i Supplied PL/SQL Packages and Types Reference, Cap 16”, Oracle Corp., 2001 RIFERIMENTI [3] http://technet.oracle.com (Oracle Technology Network) 61 CP 115