martedì 17 settembre 2013

Backup e Ripristino con Oracle


Piccola ma doverosa premessa sui backup di Oracle: come detto in altre occasioni, non c'è "tasto destro - backup".

In realtà non è cosi tragica la faccenda, ma è bene capire un paio di concetti per poter andare tranquilli.
Oracle raggruppa gli oggetti in SCHEMI, che però non sono gli stessi schemi di SqlServer, ma sono semplicemente l'insieme di tutti gli oggetti di un Utente. Ogni oggetto viene salvato logicamente in un TABLESPACE, il quale salva fisicamente oggetti e dati in uno o più datafile su filesystem, in tempi e modi che non staremo qui a vedere, altrimenti facciamo notte ( in realtà non li so, e comunque è già notte adesso).

Fin dalle versioni più vecchie di Oracle, il modo classico per effettuare e ripristinare un backup è utilizzare le utility imp ed exp. Non fanno altro che fare dei file compressi con le istruzioni di DDL e di DML necessarie per ricreare tutto quello che è stato backuppato.
Dalla versione 10g c'è anche un altro modo, il DATA PUMP. La grossa differenza tra i due metodi è che imp/exp crea/legge un file di backup dal nostro filesystem, e quindi da un client Oracle, mentre il DATA PUMP legge e scrive file di backup dal filesystem del server Oracle o da una posizione di rete raggiungibile dal server Oracle.
Altra differenza è che per eseguire un FULL export con il DATA PUMP c'è bisogno di alcuni permessi, e in generale le cartelle logiche di oracle che vedremo dopo sono soggette a permessi. E' vero che la directory di default utilizzata dal DATA PUMP è leggibile e scrivibile da tutti gli utenti per default (credo, non sono sicuro), ma non è detto che sia utilizzata quella, e quindi c'è bisogno di darsi o farsi dare i permessi per utlizzarla.
Dal punto di vista operativo queste solo le grosse differenze, mentre dal punto di vista delle possibilità, il DATA PUMP risolve una delle grandi limitazioni dell'imp/exp, ovvero i remap.

In tutti quei casi (per me è quasi la regola) in cui non dobbiamo ripristinare un backup di uno schema dello stesso utente, con stesso tablespace, l'imp/exp ci crea difficoltà. L'imp infatti quando va a ricreare gli oggetti dello schema, cerca di attribuirne la proprietà all'utente originale, che potrebbe ad esempio non esistere. In alcuni casi si riesce comunque a fare l'import ricorrendo a degli espedienti togliendo e mettendo permessi qua e la, per forzare la scrittura, ma comunque non viene mai un lavoro fatto bene e perfettamente funzionante. A maggior ragione quando si parla di passare da un tablespace all'altro l'imp da i numeri del tutto.

A questo punto ci viene in aiuto il DATA PUMP, che invece gestisce egregiamente lo spostamento di schemi e tablespace, tramite i parametri REMAP_SCHEMA E REMAP_TABLESPACE che vedremo dopo. Non si capisce invece per quale motivo il data pump non importi anche i tipi utente, ma questa è un'altra storia, tenete presente però che non lo fa e quindi in caso vanno ricreati tramite script... o almeno io non ho trovato il modo di farlo.

Il DATA PUMP addirittura tenta di ricreare l'utente dello schema esportato, ma non mi pare il caso di spingersi cosi oltre per non andare a creare un utente insomma...

Bene detto questo vediamo come esportare e importare uno schema con i due tool.

IMP/EXP
Per esportare uno schema "vecchia maniera", apriamo il prompt del dos e scriviamo

C:/> exp utente/password@connessione



EXP/IMP SU DATABASE 11G R2
Può succedere di incappare in un problema lavorando sulla versione 11G R2 di Oracle, ovvero che eseguendo l'export di una schema, vengano esportate solo le tabelle con almeno una riga al loro interno.
La ragione di questo comportamento è la nuova funzionalità della versione 11.2, ovvero la "Deferred Segment Creation" - la creazione di una tabellla è differita fino al primo insert eseguito su di essa.
Il risultato di questa funzionalità è che le tabelle vuote di fatto ancora non hanno allocato segmenti di storage e quindi non risultano nella vista "dba_segments" che il tool di export utilizza per listare le tabelle da esportare.
Questa funzionalità è controllata dal parametro deferred_segment_creation, che ha TRUE come default.
Se si imposta a FALSE, da quel momento in poi ogni tabella appena creata allocherà immediatamente dei segmenti e verrà quindi esportata dal tool di export anche se vuota.
ATTENZIONE: tutte le tabelle già create continueranno a non essere esportate fino al primo insert.
Per ovviare a questo problema, si può eseguire questo comando da pl/sql:
Alter table <tablename> allocate extent;
in questo modo la tabella alloca il suo segment e quindi verrà esportata.
Per praticità, si può ricavare la lista di tabelle presenti in una schema e autocostruirsi la lista dei comandi da lanciare per ogni tabella dello schema:
SELECT 'Alter table ' || table_name || ' allocate extent;' FROM  ALL_TABLES WHERE OWNER = '<SCHEMAOWNER>';
Se copiamo e incolliamo il risultato di questa query in pl/sql e lo eseguiamo, ogni tabella del nostro schema allocherà il suo primo segment, se non lo avesse, e potrete quindi eseguire l'export completo.

DATA PUMP
Esportazione (prima di lanciare trepidanti vedere sotto):
SO> expdp scott/tiger DIRECTORY=dmpdir DUMPFILE=scott.dmp
dove dmpdir è:
SQL> CREATE DIRECTORY dmpdir AS '/opt/oracle';
SQL> GRANT read, write ON DIRECTORY dmpdir TO scott;
Oracle cmq mette a disposizione una cartella di default il cui percorso può essere scoperto tramite l’istruzione:
SQL> SELECT directory_path FROM dba_directories WHERE directory_name = 'DATA_PUMP_DIR';
Lanciare ora l’istruzione expd con i giusti parametri.
Importazione(prima di lanciare trepidanti vedere sotto):
SO> impdp system/oracle DIRECTORY=dmpdir DUMPFILE=scott.dmp
Dove dmpdir è la stessa cosa di prima quindi se si cambia istanza ORACLE va rifatta la procedura.
Questa istruzione ripristinerà il dump con i valori di tablespace e schema di origine.
Per cambiare tablespace esiste il parametro REMAP_TABLESPACE:
SO> impdp system/oracle REMAP_TABLESPACE=tbs1:tbs2 DIRECTORY=dmpdir DUMPFILE=scott.dmp
Per cambiare schema esiste il parametro REMAP_SCHEMA:
SO> impdp system/oracle REMAP_SCHEMA=sch1:sch2 DIRECTORY=dmpdir DUMPFILE=scott.dmp
Ovviamente i parametri riguardanti tablespace e schema possono essere usati in congiunzione per un’ esperienza migliore, inoltre sarebbe cosa buona e giusta lanciare le due istruzioni (expdp e impdp) mettendo come credenziali quelle dell’utente owner dello schema di esportazione/importazione e non system o sys.

Edit:

può capitare di ricevere un errore di questo tipo :
ORA-31633: unable to create master table "QUALCOSA.SYS_IMPORT_FULL_XX" 

Banalmente, questo errore può essere dovuto a una precedente importazione andata male, per cui in quel caso è opportuno pulire tutti gli oggetti creati nel nostro schema.
Un modo veloce che uso di solito per farlo è droppare e ricreare l'utente, se i grant da dare sono pochi o se abbiamo a disposizione uno script per ricrearlo. 
Un'alternativa è quella di eseguire una query simile a questa:



SQL> select 'drop ' || object_type || ' "NOSTROSCHEMA"."' || object_name ||'";' from all_objects where owner = 'NOSTROSCHEMA';

Il risultato di questa query è una serie di drop degli oggetti dello schema che abbiamo indicato. Alternativamente, se doveste avere problemi a leggere la vista all_objects, potete eseguirla loggati come l'utente dello schema da cancellare e usare USER_OBJECTS invece di ALL_OBJECTS.
Potete a questo punto copiare/incollare il risultato in un nuovo script ed eseguirlo.
Noterete che in effetti non è lo stato dell'arte di uno script di drop, perchè non tutti gli oggetti supportano direttamente il drop, o magari la sequenza dei drop porta a droppare un oggetto che ha riferimenti in altri oggetti non ancora droppati.
In realtà potreste andare a leggere delle viste di sistema più mirate come USER_TABLES, USER_VIEWS, USER_TRIGGERS e cosi via, ma lo scopo di questo script è sbrigarsi a cancellare tutto e rifare l'import, per cui basta eseguirlo piu volte finchè non otterrete solo messaggi che vi avvisano che l'oggetto da droppare non c'è più.
Come dire, dirty and fast!