ORA-29341 bei Transportable Tablespaces

21. September 2010 Aus Von Markus Flechtner

Momentan kämpfe ich gerade gegen “Transportable Tablespaces”  von Oracle, kurz “TTS”.  TTS sind ein nettes Feature der Datenbank. Man nimmt die Datafiles und kopiert sie auf den Zielrechner, man exportiert die Metadaten aus der Ausgangsdatenbank und importiert sie auf dem Zielsystem. Und dann ist alles da. Soweit die Theorie.

Problem dabei: die Tablespaces, die man auf diese Art und Weise transferiert, müssen “self-contained” sein, d.h. es darf keine Referenzen nach draußen geben. Also: wenn ich Tabellen im Tablespace TAB_DATA habe und die zugehörigen Indizes in IND_DATA, dann muss ich beide zusammen transferieren.

Ob so ein Set “Self-Contained” ist, prüft man mit der Prozedur DBMS_TTS.TRANSPORT_SET_CHECK.

execute DBMS_TTS.TRANSPORT_SET_CHECK(‘TAB_DATA,IND_DATA’,TRUE,TRUE);

Der 1.Parameter ist die Liste der Tablespaces, mit Parameter 2 kann man angeben, ob die Constraints geprüft werden sollen und Parameter 3 “FULL_CHECK” sorgt dafür, dass nicht nur Referenzen aus dem Tablespace-Set heraus geprüft werden, sondern auch die Referenzen in das Tablespace-Set hinein. Wenn man beides auf “TRUE” setzt, dann sollte das eine vollständige Prüfung sein.

Das Ergebnis dieser Prüfung kann man dann in SYS.TRANSPORT_SET_VIOLATIONS sehen.

SELECT * FROM SYS.TRANSPORT_SET_VIOLATIONS;

Und die Dokumentation sagt: “If the view does not return any rows, then the set of tablespaces is self-contained”, sprich: man kann diese Gruppe via “TTS” in eine andere Datenbank transferieren.

Ein Export mit DataPump ergibt dann aber – in einem konkreten Fall:

Export: Release 10.2.0.4.0 – 64bit Production on Sunday, 19 September, 2010 0:16:30
Copyright (c) 2003, 2007, Oracle.  All rights reserved.
;;;
Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 – 64bit Production
With the Partitioning, Data Mining and Real Application Testing options
Starting “SYSTEM”.”EXPORT_DEMO”:  parfile=/tmp/demo.par
ORA-39123: Data Pump transportable tablespace job aborted
ORA-29341: The transportable set is not self-contained
Job “SYSTEM”.”EXPORT_DEMO” stopped due to fatal error at 00:19:26

Welche Probleme es gegeben hat, steht in der View PLUGGABLE_SET_CHECK. Dort sind dann auch weitere Informationen zu finden, z.B. welche Tabellen die Probleme machen etc.

Das generelle Problem ist nur:  der Check über DBMS_TTS.TRANSPORT_SET_CHECK bzw. TRANSPORT_SET_VIOLATIONS hat also praktisch keine Aussagekraft. Beim Export selbst erfolgt anscheinend eine wesentlich schärfere Prüfung.

Ist das jetzt ein Bug? Was wird da genau geprüft? Und wie kann man manuell diese schärfere Prüfung starten?

Die letzte Frage kann man relativ einfach beantworten. Man muss diese schärfere Prüfung nicht extra starten: die View SYS.PLUGGABLE_SET_CHECK ist auch so gefüllt. Das sieht man, wenn man sich die View-Definition anguckt. Am Ende liegt dahinter nämlich nicht eine Tabelle (die durch irgendeine Prozedur gefüllt werden müsste), sondern es sind nur Abfragen auf interne Data Dictionary-Views.

Dazu ein kleines Test-Szenario

SQL>
SQL> REM     Preparations    ====================================
SQL> create tablespace MF_TAB datafile ‘/u01/testdb/oradata/mf_tab_01.dbf’ size 50 M extent management local autoallocate segment space management auto;
Tablespace created.
SQL>
SQL> create tablespace MF_IND datafile ‘//u01/testdb/oradata/mf_ind_01.dbf’ size 50 M extent management local autoallocate segment space management auto;
Tablespace created.
SQL>
SQL> create user MF identified by MF
2  default tablespace MF_TAB;
User created.
SQL>
SQL> grant connect,resource to MF;
Grant succeeded.
SQL>
SQL> create table MF.MF_OBJECTS tablespace MF_TAB as select * from ALL_OBJECTS where rownum < 1000;
Table created.
SQL>
SQL> CREATE INDEX MF.MF_OBJ_IND on MF.MF_OBJECTS (OBJECT_ID) tablespace MF_IND;
Index created.
SQL>
SQL>
SQL> set linesize 1000
SQL> set trimspool on
SQL> select tablespace_name,segment_type,segment_name
2  from dba_segments where owner = ‘MF’;
TABLESPACE_NAME                SEGMENT_TYPE       SEGMENT_NAME
—————————— —————— ———————————————————————————
MF_TAB                         TABLE              MF_OBJECTS
MF_IND                         INDEX              MF_OBJ_IND
SQL>
SQL>
SQL> REM     Check for violations ==========================================
SQL> select ts1_name,ts2_name,reason from sys.pluggable_set_check
2  where ts1_name in (‘MF_TAB’,’MF_IND’)
3  or ts2_name in (‘MF_TAB’,’MF_IND’)
4  ;
TS1_NAME                       TS2_NAME                       REASON
—————————— —————————— ————————————————————————————–
MF_TAB                          MF_IND                        Tables and associated indexes not fully contained in the pluggable set

OK, in diesem Fall ist die “violation” offensichtlich und mit DBMS_TTS.CHECK_TRANSPORT_SET wird das gleiche Problem ermittelt, aber wichtig ist:

Auch ohne DBMS_TTS.CHECK_TRANSPORT_SET auszuführen, kann man solche Probleme rausfinden.

PLUGGABLE_SET_CHECK ist zwar eine sehr große View und ein SELECT darauf kann bei größeren Datenbanken etwas dauern, aber man kann z.B. vorher einen

CREATE TABLE TABLESPACE_VIOLATIONS
AS SELECT DISTINCT TS1_NAME,TS2_NAME
FROM SYS.PLUGGABLE_SET_CHECK;

machen, wenn man mehrere dieser Prüfungen ausführen möchte. Dadurch hat man die ganzen Informationen in einer Tabelle und kann wesentlich schneller darauf zugreifen.

Es bleibt die Frage, ob dieses Verhalten so beabsichtigt ist oder ob es ein Bug ist, denn theoretisch sollte ja DBMS_TTS.TRANSPORT_SET_CHECK auch alle Violations ermitteln. Leider ließ sich das nicht mehr verifizieren, denn das Leben geht weiter und mein Kunde brauchte das System für weitere Tests und hat die fraglichen Tablespaces kurzerhand gelöscht. Und die Migration, die wir eigentlich mit “Transportable Tablespaces” machen wollten, hat der Kunde – u.a. aufgrund dieses merkwürdigen Verhaltens – mit einem anderen, selbst programmierten Verfahren (erfolgreich) durchgeführt.