Alles was man beim EXPDP/IMPDP beachten sollte!

Wenn Daten zwischen Oracle Datenbanken übertragen werden müssen, und keine Datenbank Links genutzt werden können, bietet sich EXPDP/IMPDP für diese Aufgabe an.

Gleich vorweg: EXPDP/IMPDP ist keine valide Backup Lösung, da dies nur eine Momentaufnahme erstellt, und somit per Definition alle nachfolgenden Änderungen verloren gehen. Außerdem muss explizit dafür gesorgt werden, dass der erzeugte Dump konsistent ist – dazu später mehr – und beim Importieren per IMPDP kann es auch die eine oder andere Überraschung geben.

In diesem Artikel beschreibe ich die typischen Probleme und deren Lösungen, setze aber bei den Beispielen mindestens Oracle 12c voraus, da erst ab dieser Version in den Views DBA_USERS und DBA_ROLES die Spalte ORACLE_MAINTAINED vorhanden ist. Bei älteren Oracle Versionen müssen in die Abfragen leider hardcoded die entsprechenden Benutzer aufgenommen werden.

Der Artikel berücksichtig nicht die vielen Optionen, mit denen Objekte manipuliert oder umbenannt werden können.

Wie exportiert man richtig?

Es gibt seitens EXPDP viele Varianten beim Exportieren (FULL, SCHEMA, TABLE). In allen Fällen kann es beim Import zu unvorhergesehenen Problemen kommen. Damit nicht erst beim IMPDP auffällt, dass Informationen fehlen, empfehlen wir immer einen FULL Database Export zu machen. 

FULL Database Export – zu exkludierende Schemas

Bei einem FULL Database Export dürfen die von Oracle erzeugten Schemas nicht mitgenommen werden. Welche dies sind, kann folgende Abfrage beantworten:

Für Unix:

SELECT listagg('\'''||username||'\''',',') within group(order by username) 
  FROM dba_users 
 WHERE oracle_maintained='Y' or username like 'APEX%'; 

Für Windows:

SELECT listagg(''''||username||'''',',') within group(order by username) 
  FROM dba_users 
 WHERE oracle_maintained='Y' or username like 'APEX%'; 

Diese Liste an Namen wird dem Parameter 
    EXCLUDE=SCHEMA::\“IN \(<output_der_query>\)\“ 
beim EXPDP oder IMPDP mitgegeben.

APEX schließe ich zusätzlich ein – den Grund beschreibe ich am Ende dieses Artikels. Natürlich könnte man beim EXPDP alle Schemas mitnehmen, dann müssten aber die Oracle Schemas beim IMPDP exkludiert werden, da es sonst zu Fehlern kommt.

UNIFIED AUDIT exkludieren

In den meisten Fällen wird man die Informationen aus UNIFIED AUDIT nicht übertragen wollen. Auch wenn das Schema AUDSYS exkludiert wird, werden die Daten trotzdem exportiert.

Damit das verhindert werden kann, muss beim EXPDP folgende Option mitgeben werden: EXCLUDE=AUDIT_TRAILS

EXPDP konsistent erzeugen

Das Default Verhalten ist, dass der EXPDP jede Tabelle für sich lesekonsistent exportiert. Wird das so belassen, gibt es beim Import Probleme, weil die Tabellen untereinander zu verschiedenen Zeitpunkten konsistent sind. 

Um das zu verhindern, muss der Parameter FLASHBACK_TIME (oder FLASHBACK_SCN) gesetzt werden – siehe Beispiel weiter unten.

Wo sollen die EXPDP / IMPDP Files liegen?

Das/die erzeugten Dumpfile(s) landen in einem Datenbank Directory. Oracle bringt ein Default Directory mit dem Namen DATA_PUMP_DIR mit, dass auf $ORACLE_BASE/admin/<ORACLE_SID>/dpdump zeigt. In vielen Fällen ist dort im Filesystem aber nicht ausreichend Platz, daher sollte im Vorfeld ein Database Directory für eine passende Location angelegt werden:

CREATE DIRECTORY MY_DUMPDIR as '/verzeichnis/mit/viel/platz/';

Beispiel für einen sinnvollen FULL Database Export

Dieses Beispiel enthält die zuvor besprochenen Parameter, wobei das EXCLUDE=SCHEMA auch erst beim IMPDP genutzt werden kann.

Hinweis: alles in eine Zeile. Alternativ kann man die Parameter auch in ein Parameterfile schreiben und dieses beim Aufruf von EXPDP angeben.

expdp "'/ as sysdba'" full=y directory=MY_DUMPDIR dumpfile=full_expdp.dmp
      logfile=full_expdp.log flashback_time=systimestamp 
      EXCLUDE=AUDIT_TRAILS EXCLUDE=SCHEMA:\"IN \( \'ANONYMOUS\',\'APPQOSSYS\',\'AUDSYS\',\'CTXSYS\',\'DBSFWUSER\',\'DBSNMP\',\'DIP\',\'DVF\',\'DVSYS\',\'GGSYS\',\'GSMADMIN_INTERNAL\',\'GSMCATUSER\',\'GSMROOTUSER\',\'GSMUSER\',\'LBACSYS\',\'MDDATA\',\'MDSYS\',\'OJVMSYS\',\'OLAPSYS\',\'ORACLE_OCM\',\'ORDDATA\',\'ORDPLUGINS\',\'ORDSYS\',\'OUTLN\',\'REMOTE_SCHEDULER_AGENT\',\'SI_INFORMTN_SCHEMA\',\'SYS\',\'SYS$UMF\',\'SYSBACKUP\',\'SYSDG\',\'SYSKM\',\'SYSRAC\',\'SYSTEM\',\'WMSYS\',\'XDB\',\'XS$NULL\'\)\"

Was sollte vor dem IMPDP gemacht werden, um Probleme zu vermeiden?

Das ist keine vollständige Auflistung! Es sind nur die mir in der Praxis am häufigsten untergekommenen Probleme. Der Full Database Import macht mehr als der Schema Import – in diesem Artikel wird nur der Full Database Import betrachtet. Aus Performancegründen sollte die Ziel Datenbank nicht im Archivelog Modus sein.

Tablespaces, Datafiles und Pfade

Der EXPDP (FULL DATABASE) und der IMPDP legen zwar Tablespaces und Datenbankfiles an, nicht immer will man die aber 1:1 übernehmen!

Die folgende Abfrage erzeugt CREATE TABLESPACE Statements, wobei die Pfade für die Datenbankfiles entsprechend korrigiert werden müssen:

SELECT 'CREATE ' || decode (CONTENTS,'PERMANENT','',CONTENTS) || 
       ' TABLESPACE ' || TABLESPACE_NAME || ' ' || 
       decode(contents,'TEMPORARY','TEMP','DATA') ||
       'FILE ''d:\oradata\MYDB\' || TABLESPACE_NAME || 
       '.dbf'' SIZE 100M  AUTOEXTEND ON NEXT 100M;' 
  FROM dba_tablespaces 
 WHERE tablespace_name not in ('UNDOTBS','SYSTEM','SYSAUX','TEMP', 
                               'USERS', 'UNDOTBS1','UNDOTBS2','UNDOTBS01');  

Allerdings legt das Statement pro Tablespace nur ein Datenbankfile an. Das kann unter Umständen zu wenig sein. Wenn die Datenbank größer ist, kann folgendes PLSQL Programm eingesetzt werden, um eine ausreichende Anzahl an Datenbankfiles pro Tablespace zu bekommen.

set serveroutput on;
declare
begin
 for t in ( select 'CREATE ' || decode (CONTENTS,'PERMANENT','',CONTENTS)
            ||' TABLESPACE ' || TABLESPACE_NAME || ' ' || 
            decode(contents,'TEMPORARY','TEMP','DATA')|| 
            'FILE ''d:\oradata\MYDB\' || TABLESPACE_NAME || 
            '.dbf''  SIZE 100M  AUTOEXTEND ON NEXT 100M;'  as text
              from dba_tablespaces 
             where tablespace_name not in
                  ('UNDOTBS','SYSTEM','SYSAUX','TEMP', 'USERS',
                   'UNDOTBS1','UNDOTBS2','UNDOTBS01'))
 loop
  dbms_output.put_line(t.text); 
 end loop;
 
 for i in (
  Select round((a.used_GB/20),0) as anz_files, a.tablespace_name
    from ( select sum(bytes/1024/1024/1024) used_GB, tablespace_name 
             from dba_segments 
            group by tablespace_name) a
   where a.used_GB/20 >= 1)
 loop
  FOR b IN  1..i.anz_files
  LOOP
   /* Der folgende Befehl muss in einer Zeile stehen */
   dbms_output.put_line('ALTER TABLESPACE '|| i.tablespace_name || 
                        ' ADD DATAFILE ''d:\oradata\MYDB\' ||
                        i.TABLESPACE_NAME || b || 
                        '.dbf''  SIZE 100M AUTOEXTEND ON next 100M;');
  END LOOP;
 end loop;
end;
/

Durch die Berechnung round((a.used_GB/20),0) wird festgelegt, dass ein Datenbankfile beim IMPDP voraussichtlich maximal 20GB groß werden soll. Damit ist noch Raum für Wachstum vorhanden, ohne dass gleich weitere Datenbankfiles angelegt werden müssen.

Applikationsrollen sollten vor dem Import existieren

EXPDP kann GRANTS auf Rollen enthalten, bevor die Rollen überhaupt durch den IMPDP angelegt werden. Dadurch gehen diese Grants verloren und das endet oft in Troubleshooting, weil die Applikation nicht funktioniert. Natürlich können die fehlgeschlagenen GRANTS aus dem IMPDP Logfile extrahiert werden, das kann aber aufwendig sein. Daher ist es zu empfehlen, die Rollen schon im Vorfeld anzulegen.

Bei normalen Rollen geht das ganz einfach, nur bei Rollen mit Passwort oder anderer Authentication wird es komplizierter. Die folgende Query gibt aus, welche Rollen in der Datenbank angelegt wurden und ob diese ein Passwort oder eine andere Authentifizierung nutzen – in diesem Fall muss entsprechend mehr getan werden:

select ROLE, PASSWORD_REQUIRED, AUTHENTICATION_TYPE, COMMON 
  from dba_roles where  oracle_maintained='N';

Sofern hier in PASSWORD_REQUIRED nicht NO ist und in AUTHENTICATION_TYPE nicht NONE steht, muss mit den Applikationsverantwortlichen geklärt werden, was dafür benötigt wird. In diesem Fall ist es meistens einfacher, wirklich die fehlgeschlagenen GRANTS aus den IMPDP Logfiles zu extrahieren.

In allen anderen Fällen liefert das folgende Statement die CREATE ROLE Statments, die dann einfach vor dem Import in die Datenbank eingespielt werden:

select 'CREATE ROLE ' || ROLE ||';' as STMT 
  from dba_roles 
 where oracle_maintained='N' 
   and PASSWORD_REQUIRED='NO' 
   and AUTHENTICATION_TYPE='NONE';

Applikations-Objekte im Schema SYS angelegt

Grundsätzlich sollten Objekte, die zur Applikation gehören, niemals im Schema SYS angelegt werden. Es gibt jedoch Situationen, wo es wirklich nicht anders geht. In diesem Fall gehört dies explizit dokumentiert! Leider ist das in der Praxis oft nur ein frommer Wunsch. Die typische Situation ist oft, dass es entweder nie dokumentiert wurde oder sich niemand an die Dokumentation erinnern kann.

Somit ergibt sich die Frage:

Wie könnte man diesen Umstand erkennen?

Das hängt davon ab, wie und wann die Datenbank erzeugt wurde und wann die Applikationsobjekte erzeugt wurden. Sofern dies nicht am gleichen Tag erfolgt ist, kann mit folgenden Abfragen versucht werden, die Objekte zu identifizieren:

with ZEITPUNKTE AS
(select OWNER, TRUNC(CREATED) AS OBJECT_ERZEUGT, COUNT(*) ANZAHL 
from DBA_OBJECTS 
where OWNER='SYS'
group by OWNER, TRUNC(CREATED)
having COUNT(*) < 10)
select OWNER, OBJECT_NAME, OBJECT_TYPE, CREATED, LAST_DDL_TIME
  from DBA_OBJECTS
 where TRUNC(CREATED) in (select OBJECT_ERZEUGT from ZEITPUNKTE)
   and OWNER not in (select USERNAME from DBA_USERS where ORACLE_MAINTAINED='Y' and username <>'SYS')
   and OBJECT_NAME not like 'WRI$_OPTSTAT%'
   and OBJECT_NAME not like 'SYS_IL%$$'
   and OBJECT_NAME not like 'SYS_LOB%$$'
   and OBJECT_NAME not like 'WRP$_REPORTS%'
   and not (OWNER='PUBLIC' and OBJECT_TYPE='SYNONYM')
 order by CREATED, OWNER, OBJECT_NAME;

Was macht diese Anfrage genau?

In der WITH Query werden zuerst jene Zeitpunkte (Tage) ermittelt, an denen im Schema SYS maximal 10 Objekte angelegt wurden – typischerweise werden von Applikationen nur wenige Objekte im SYS Schema angelegt. Mit diesen Zeitpunkten wird dann nochmals überprüft, welche Objekte (ausgenommen die Oracle Datenbank Schemas) zum gleichen Zeitpunkt mit diesen Objekten im SYS-Schema angelegt wurden. In der Regel werden ja die SYS-Schema Objekte gemeinsam mit den Applikationsobjekten im Applikationsschema angelegt.

Das Ergebnis ist eine Liste aller Objekte, die im Applikationsschema und im SYS Schema am gleichen Tag erzeugt wurden. Die zusätzlichen Ausschließungen von bestimmten Objekt Namen und Typen sorgt nur dafür, dass Oracle-interne Objekte nicht gewertet werden. Die Ausgabe muss nun durchgegangen werden und man kann somit erkennen, welche Objekte im Schema SYS potentiell zur Applikation gehören könnten. Natürlich wird es dabei einige FALSE-Positiv geben, ganz ohne Nachdenken und Checken der Objekte wird es nicht gehen.

Importieren mit IMPDP

Sobald die Vorarbeiten erledigt sind, gestaltet sich der IMPDP in der Regel recht einfach. Nachdem das Datenbank Directory wieder angelegt wurde, kann der IMPDP erfolgen.

CREATE DIRECTORY MY_DUMPDIR as '/verzeichnis/mit/viel/platz/';

impdp "'/ as sysdba'" DIRECTORY=MY_DUMPDIR FULL=y dumpfile=full_expdp.dmp logfile=full_impdp.log 

Nacharbeiten nach dem IMPDP

Je nachdem, welche Funktionalitäten genutzt werden, sind noch einige Nacharbeiten zu erledigen.

Objekt Grants von SYS an andere Schemas oder Rollen

Werden an Benutzer oder Rollen direkt vom SYS Schema aus Rechte gegrantet, wird dies nicht mitgenommen. Das folgende Statement erzeugt die fehlenden Grants inkl. aller PUBLIC Grants – hier kann man nicht feststellen, ob diese seitens Oracle oder eines DBAs vergeben wurden. Da es bei Oracle kein Problem ist, wenn es den gleichen Grant mehrfach gibt, ist dies aber kein Problem.

select 'grant '||privilege||' on '||owner||'.'||table_name
       ||' to '||grantee||';' as STMT
  from dba_tab_privs 
 where owner='SYS' 
   and GRANTEE not in (select USERNAME from DBA_USERS 
                        where ORACLE_MAINTAINED='Y' 
                        union all 
                       select ROLE from DBA_ROLES  
                        where ORACLE_MAINTAINED='Y');

Java Grants von SYS an andere Schemas oder Rollen

Leider werden auch Java Grants nicht automatisch mitgenommen. Die folgende Query liefert die Informationen, welche Grants möglicherweise fehlen. Am besten den Output von der Quelle mit dem Ziel vergleichen.

select TYPE_SCHEMA, TYPE_NAME, NAME, GRANTEE, ENABLED
  from dba_java_policy 
 where grantee not in (select USERNAME from DBA_USERS 
                        where ORACLE_MAINTAINED='Y' 
                        union all 
                       select ROLE from DBA_ROLES  
                        where ORACLE_MAINTAINED='Y')
    and kind = 'GRANT';

Proxy User

Weiters gibt es sehr oft Probleme mit PROXY Usern. Der Grund ist, dass die CONNECT THROUGH Berechtigung beim EXPDP nicht mitgenommen wird.

Das folgende Statement erzeugt die benötigten ALTER USER Statements:

select 'alter user "'||client||'" grant connect through "'||proxy||'";' 
       as STMT 
  from proxy_users;

Application Context

Nutzt die Applikation „Application Context“, sollte immer verifiziert werden, dass diese korrekt angelegt wurden:

select 'CREATE OR REPLACE CONTEXT '||NAMESPACE||
       ' USING '||SCHEMA||'.'||PACKAGE||' '||TYPE||';' 
  from dba_context 
 where schema not in (select username from dba_users 
                       where oracle_maintained='Y');

Invalide Objekte

Nach einem IMPDP sind in der Regel viele Objekt invalid. Nach einem Rebuild mittels folgendem Aufruf

sqlplus / as sysdba
@?/rdbms/admin/utlrp.sql
exit;

sollte verifiziert werden, welche Objekte in der Quell- und Ziel-Datenbank invalid sind – es sollten die gleichen Objekte sein!

select owner,object_name, object_type 
  from dba_objects 
 where status <>'VALID';

Hinweis: Sind in der Quelldatenbank mehr Objekte invalid, sollt dort ebenfalls mittels UTLRP.sql ein Rebuild gestartet und erneut geprüft werden!

Database Directories

Oft werden Database Directories als Benutzer SYS angelegt oder die Pfade modifiziert. Diese werden vom EXPDP leider nicht mitgenommen!

select * from dba_directories;

Sowohl in der Quell- als auch dier Ziel-Datenbank ausgeben und vergleichen. Wenn es Unterschiede gibt, müssen diese entsprechend korrigiert werden.

Database Links

Wenn Datenbank Links als Benutzer SYS angelegt wurden, werden diese ebenfalls nicht exportiert. So kann das in der Quell-Datenbank geprüft werden:

select owner, DB_LINK, USERNAME, HOST, CREATED 
  from dba_db_links 
 where OWNER = 'SYS';

Network ACLs

Auch Netzwerk ACLs werden durch EXPDP nicht übernommen und müssen manuell nachgetragen werden. Da die dazugehörigen Statements den Rahmen dieses Artikels sprengen würden: Hier ist ein Link, wo eine entsprechende Anleitung zu finden ist:

Oracle Text Indizes 

Leider gibt es auch immer wieder Probleme beim Übertragen der Oracle Text Indizes. Im ersten Schritt wird in Quelle und Ziel überprüft, ob alle Indizes vorhanden sind:

select index_name, table_name, index_type 
  from dba_indexes 
 where ityp_owner='CTXSYS' 
   and ityp_name='CONTEXT' 
 order by 1,2;

Sind diese nicht gleich, kann man sich für jeden FEHLENDEN Index die Definition aus der Quelldatenbank auslesen:

set long 500000 
select ctx_report.describe_index('NAME_DES_FEHLENDEN_INDEX') 
  from dual; 
select ctx_report.create_index_script('NAME_DES_FEHLENDEN_INDEX') 
  from dual;       

Sobald alle Indizes in der Zieldatenbank angelegt wurden, sollte unbedingt noch überprüft werden, ob auch Daten vorhanden sind:

SELECT c.idx_owner,c.idx_name,i.TABLE_NAME,c.idx_text_name,
       c.idx_type,c.idx_docid_count,
       i.status,i.domidx_status,i.DOMIDX_OPSTATUS 
  FROM ctxsys.ctx_indexes c, dba_indexes i 
 WHERE c.idx_name=i.index_name ORDER BY 2,3;

Der Status muss auf VALID stehen und in der Spalte idx_docid_count findet sich die Anzahl der Records (DOCIDs). Das folgende Statement erzeugt Select Statements, die den Aufbau der Indizes anstoßen:

SELECT   'SELECT ctx_report.create_index_script (''' || c.idx_owner 
         || '.' || c.idx_name || ''') AS line_ FROM dual;'
  FROM ctxsys.ctx_indexes c, dba_indexes i WHERE c.idx_name=i.index_name
 WHERE i.status <> 'VALID'
    or i.domidx_status <> 'VALID' 
    or c.idx_docid_count = 0 ;

Zum Abschluss sollte man für den Index noch einen Sync durchführen, wenn es Pending Records gibt. Das folgende Statement erzeugt die dazu nötigen Befehle:

select 'exec ctxsys.ctx_ddl.sync_index(idx_name =>''' || 
       PND_INDEX_OWNER || '.' || PND_INDEX_NAME ||''');' 
  from ctxsys.CTX_PENDING;

Weiterführende Themen

Ziel Datenbank

Beim Anlegen der Ziel Datenbank muss man viele Punkte beachten, unter anderem:

  • Zeichensatz (will man den gleichen Zeichensatz oder soll dieser konvertiert werden)
  • Blocksize
  • Global_database_name – mit oder ohne domain?
  • ONLINE Logfiles in der richtigen Größe anlegen
  • Prüfen der Passwortlimits (Profiles)
  • Alle notwendigen Datenbank Optionen installieren (am besten nur die nötigen, nicht alle). Eventuell vorher prüfen was wirklich verwendet wird?
    Siehe auch folgende Webinare:
    Oracle Datenbank Optionen: Welche gibt es?
    Unnötige Optionen in der Oracle DB vermeiden
  • Netzwerkkonfigurationsfiles (Listener.ora, sqlnet.ora, tnsnames.ora, Oracle Wallets)

APEX

Im Fall von APEX ist es empfehlenswert wie folgt vorzugehen:

  • APEX in der aktuellsten Version in der Ziel Datenbank installieren.
  • Mittels APEX die Applikation in der Quell Datenbank exportieren.
  • Mittels APEX in der Ziel Datenbank die Applikation wieder einspielen.

Man kann APEX auch mit EXPDP/IMPDP übernehmen, sofern in der Ziel Datenbank kein APEX vorhanden ist. Dann gibt es aber immer wieder Probleme mit Berechtigungen und Ähnlichem, daher empfehlen wir die oben genannte Vorgangsweise.

ORA-01555

Kommt es beim EXPDP zu einem ORA-01555 muss man die UNDO_RETENTION höher setzen (auf die Dauer des Exports) oder am UNDO Tablespace RETENTION GUARANTEE einstellen. Gegebenfalls muss man den UNDO Tablespace vergrößern.

  • ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;
  • EXPDP durchführen
  • ALTER TABLESPACE undotbs1 RETENTION NOGUARANTEE;

Multitenant Database / Pluggable Database

Hier muss man sich mit beim Export direkt an der Pluggable Datenbank anmelden! Meldet man sich nur an der CDB an, wird praktisch nichts exportiert werden.

EXPDP/IMPDP Performance und Laufzeit

Abhängig von der Datenbank (Standard oder Enterprise Edition) gibt es mehrere verschiedene Wege um den EXPDP/IMPDP deutlich beschleunigen. Da dies von mehreren Faktoren abhängt, muss man sich das im Detail genauer anschauen.

Meine Kollegen bei DB Masters unterstützen Sie gerne bei jedem Thema rund um EXPDP/IMPDP!

Comments

  1. Jochen H.

    Danke für die Zusammenfassung.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

This site uses Akismet to reduce spam. Learn how your comment data is processed.