Datenbank-Migration
Dieser Artikel beschreibt die für die Migration einer Oracle Datenbank zum UTF8 Zeichensatz nötigen Schritte. Er geht dabei von einer Oracle 9i Datenbank aus, die den Zeichensatz WE8ISO8859P15 (Latin 15) verwendet – sollte aber prinzipiell auch auf andere Konfigurationen zutreffen.
Inhalt
- Datenbereinigung
- Daten Integrität
- Zeichensatz-Bereinigung
- Vorbereitung der Datenbank-Strukturen
- Datentransfer: Vergleich verschiedener Strategien
- Fazit
Datenbereinigung
Bevor wir uns der eigentlichen Migration zuwenden können, sollten bzw. müssen wir in unserer bestehenden Datenbank zunächst ein wenig aufräumen. Dafür gibt es mehrere gute Gründe:
- Weniger Daten haben eine schnellere Migration zur Folge, und helfen somit, die Downtime möglichst gering zu halten
- Weniger Daten bedeuten weniger Quellen für mögliche Zeichensatz-Konflikte
- Weniger Daten führen zu besserer Performanz aufgrund kürzerer Zugriffszeiten
- Weniger Daten benötigen weniger Platz (ja, wirklich!)
- Eine Reduzierung der Datenmenge beschleunigt sowohl Backup als auch Restore (und spart so im Ernstfall wertvolle Zeit)
Dies nennt nur einige Punkte – zeigt aber auch, dass eine Datenbereinigung nicht nur für den Migrationsprozess hilfreich ist, sondern auch darüber hinaus einige positive Aspekte für die spätere tägliche Arbeit und Wartung mitbringt. Sollte es daher in der Datenbank Daten geben, die nicht mehr benutzt werden können oder sollen: Ein guter Zeitpunkt, damit aufzuräumen. Auch wenn es dann letztendlich vielleicht doch nicht zu einer Migration kommen sollte …
Löschkandidaten identifizieren
In jeder Datenbank finden sich nach einer gewissen Laufzeit Tabellen, die nicht länger genutzt werden - und daher nach einem optionalen Export (Backup für den Fall des Falles) gelöscht werden können. Diese lassen sich grob in drei Kategorien einteilen:
- Tabellen, die (eigentlich temporär) für einmalige Aufgaben angelegt – und nach deren Abschluss zu löschen vergessen wurden
- Obsolete Tabellen, die bereits zur Löschung "markiert" wurden (aber immer noch nicht gelöscht worden sind)
- Tabellen, die z. B. von einer früheren Version einer Anwendung stammen, welche diese aber in der aktuellen Version gar nicht mehr nutzt
Darüber hinaus wären da noch komplette Schemata (z. B. von ehemaligen Anwendungen oder Mitarbeitern), die nicht mehr genutzt werden – und sich ebenfalls in obige Kategorien einordnen ließen. Außerdem wären da noch "historische" Datensätze, auf die nicht mehr zugegriffen wird – und die daher ebenso behandelt werden können.
Einmal sicher identifiziert, sollten diese Objekte zügig gesichert und anschließend gelöscht werden – bevor sie erneut in Vergessenheit geraten.
Daten Integrität
Eine Verifikation der Logik der Datenbankschemen fördert häufig etliche fehlende Fremdschlüssel ("Foreign Key Constraints") zutage, deren Verwaltung man einfach der jeweiligen Applikation überließ. Schaut man sich nun an, wie gut selbige dies gehandhabt hat, findet man nicht selten einige "Witwen und Weisen" ("Orphans" – Daten ohne Bezug, die für sich genommen, also ohne ihren nicht mehr vorhandenen Kontext, keinen Sinn mehr ergeben). Auch wenn es in dieser Formulierung "unethisch" klingen mag, sollte der DBA hier zum "Witwen-und-Waisen-Mörder" werden – diese Daten braucht wahrlich keiner mehr.
Zum Auffinden dieser "Orphans" ist natürlich eine gute Kenntnis des Datenmodells erforderlich. Weitere Indikatoren sind Constraints, die nicht aktiviert bzw. zwar aktiviert, aber nicht verifiziert sind. Hier gilt es zu entscheiden, ob diese Constraints dem Datenmodell zufolge sinnvoll sind – wenn ja, sollten sie aktiviert und verifiziert, andernfalls entfernt werden. Wobei das Verifizieren ("validate") wahrscheinlich erneut einige "Witwen und Waisen" zutage fördern wird, die es sodann ebefalls zu löschen gilt.
Um in Zukunft derartige "Orphans" zu vermeiden, sollten die fehlenden Fremdschlüssel nun zügig angelegt werden – natürlich nachdem mögliche Nebeneffekte in den jeweiligen Applikationen (die z.B. beim "Selbstversuch" auf Constraint-Verletzungen stoßen könnten) ausgeschlossen wurden. Etwa notwendige Anpassungen in diesen Applikationen sollten dann zeitgleich mit den neuen Constraints aktiviert werden.
Problematische Objekte
Zusätzlich zu oben bereits diskutierten Objekten, gibt es noch weitere Dinge, die in Bezug auf die Datenintegrität geprüft werden sollten:
- De-aktivierte Trigger
- Invalide Indices
- Andere invalide/defekte Objekte (Funktionen, Views, Packages, Jobs, etc.)
- Objekte ohne (oder mit veralteten) Statistiken
Folgendes SQL Skript sucht diese möglichen Unruhestifter aus der Datenbank, und listet sie auf. Die gefundenen Objekte sollten sorgfältig inspiziert werden, da ihre Bedeutung von "völlig unwichtig" bis "kritisch" reichen kann: Einige Trigger sind evtl. mit gutem Grund deaktiviert (und sollten keineswegs aktiviert, sondern besser gelöscht werden – damit sie nicht versehentlich nach der Migration aktiviert werden) - während einige Statistiken vielleicht nur "veraltet" sind, weil die zugrunde liegenden Daten statisch sind (z.B. Postleitzahlen oder ähnliche "Lookup-Tabellen").
-- -- Discover possible problematic objects -- -- Author: AI Rehberg -- $LastChangedDate: 2007-08-31 15:04:37 +0200 (Fr, 31 Aug 2007) $ -- disabled triggers select * from dba_triggers where status != 'ENABLED' and owner not in 'SYS' order by owner -- Invalid objects (packages,views,...) select owner,object_name "Object",object_type "OType",status,temporary "Temp" from dba_objects where status != 'VALID' and owner not in ('SYS') order by owner -- Possible broken packages/procedures/views/... -- (may give detail information on above selected broken objects select distinct owner,name,type,line,position,text from dba_errors where text not like '%Statement ignored%' order by owner,name -- Disabled constraints select owner,constraint_name,constraint_type "CType",table_name,status,validated,last_change from dba_constraints where 1=1 and status !='ENABLED' and owner not in ('SYS','SYSTEM','WMSYS') order by owner -- Not validated constraints select owner,constraint_name,constraint_type "CType",table_name,status,validated,last_change from dba_constraints where 1=1 and validated!='VALIDATED' and owner not in ('SYS','SYSTEM','WMSYS') order by owner -- Indices with outdated or no statistics select owner,index_name,index_type "IType",table_name,uniqueness,tablespace_name,logging "Log",status,last_analyzed,temporary "Temp" from dba_indexes where 1=1 and owner not in ('SYS','SYSTEM','WMSYS','CSMIG','CTXSYS','MDSYS','ORDSYS','OUTLN','TOAD','XDB') and (last_analyzed is null or last_analyzed < add_months(sysdate,-2)) order by owner -- Invalid indices select owner,index_name,index_type "IType",table_name,uniqueness,tablespace_name,logging "Log",status,last_analyzed,temporary "Temp" from dba_indexes where 1=1 and owner not in ('SYS','SYSTEM','WMSYS','CSMIG','CTXSYS','MDSYS','ORDSYS','OUTLN','TOAD','XDB') and status != 'VALID' order by owner |
Zeichensatz-Bereinigung
Dieses Thema betrifft hauptsächlich zwei Probleme, und resultiert in einem Double-Check der Datenbank sowie ggf. Änderungen bzgl. der Umgebungsvariablen:
- Falsche Zeichen in der Datenbank
- Zu konvertierende Zeichen in der Datenbank
Das erste Problem, so es denn besteht, wurde mit großer Wahrscheinlichkeit von
falsch (oder gar nicht) gesetzten Umgebungsvariablen verursacht. Wichtigster
Kandidat ist hier die (oft missverstandene) Variable NLS_LANG, die den
Zeichensatz der Client-Applikation (und nicht den der Datenbank)
beinhalten muss. Oftmals wurde hier stattdessen – unabhängig von den vom Client
selbst verwendeten Tatsachen – einfach der Datenbank-Zeichensatz (in unserem
Beispiel also 'WE8ISO8859P15') eingestellt. Verwendet der Client nun
tatsächlich einen anderen Zeichensatz (bei Windows üblicherweise
'WE8MSWIN1252' – auch als Windows-1252 bekannt), kommt es zu eben diesem
Problem: Der Oracle Server geht davon aus, dass die ihm übermittelten Zeichen
in dem durch NLS_LANG definierten Zeichensatz (hier: Latin-15) sind, und
speichert sie als solche ab. Eine spätere Konvertierung geht also von falschen
Tatsachen aus – sodass die meisten Sonderzeichen zerstört werden. Dies würde
also auch in jedem Fall passieren, wenn wir unsere Datenbank konvertieren, ohne
dieses Problem zuvor gelöst zu haben – statt der Sonderzeichen sehen wir dann
nur noch Fragezeichen.
Das zweite Problem ist einfach nur das, um welches wir uns ja gerade kümmern
wollen: Da wir unsere Datenbank auf den Zeichensatz 'AL32UTF8' (UTF8)
umstellen wollen, müssen einige Zeichen konvertiert werden. Glücklicherweise
ist UTF8 ein sogenanntes "Super-Set" unseres Ausgangszeichensatzes Latin-15
(d.h., alle Zeichen von Latin-15 gibt es auch in UTF8), so dass diese
Konvertierung kein großes Problem darstellen sollte.
Korrektur falscher Zeichen in der Datenbank
Wie oben bereits geschildert: Ohne Korrektur würden diese falschen Zeichen einfach durch Platzhalter ersetzt (i. d. R. ein Fragezeichen, oder ein auf dem Kopf stehendes Fragezeichen) – eine korrekte automatische Umwandlung ist nicht möglich. Unsere Korrektur erfolgt nun in drei Schritten:
- Identifizierung der betroffenen Daten
- Ersetzen der falschen Zeichen
- Berichtigen der Umgebungsvariablen (d. h. z. B., unter Windows
NLS_LANG=WE8MSWIN1252verwenden)
Bei unserem ersten Schritt unterstützt uns Oracles Character Set
Scanner (CSScan). Um unsere Problemfälle zu identifizieren, geben
wir einfach vor, wir würden von unserem derzeitigen Zeichensatz in eben
denselben konvertieren wollen (wir verwenden also WE8ISO8859P15
sowohl für den "from" als auch den "to" Zeichensatz).
CSScan wird nun alle Datensätze auflisten, deren
Zeichen nicht alle in Latin-1 gehalten sind (in userem Beispiel also alle
Spezialzeichen aus dem Windows-1252 Zeichensatz). Alle Zeilen, die bei einem
derartigen Lauf als "not convertible" (nicht konvertierbar) aufgeführt werden,
müssen nun zunächst manuell korrigiert werden – und zwar bevor wir mit dem
nächsten Schritt fortfahren.
Zu konvertierende Zeichen
Nachdem alle "falschen Zeichen" korrigiert sind (siehe oben) –
d. h. unsere Datenbank ausschließlich Zeichen enthält, die ihrem verwendeten
Zeichensatz entsprechen – und nicht vorher, können wir auf die Folgen unserer
Konvertierung prüfen. Der Prozess läuft ähnlich wie der vorige – nur geben wir
dieses Mal den Zeichensatz als Ziel an, zu dem wir auch tatsächlich
konfertieren wollen: AL32UTF8. Das Ergebnis dieses Character Set Scanner
Laufes teilt unsere Daten in 4 Kategorien auf:
- Changeless: Keine Änderungen
- Convertible: Die notwendigen Korrekturen erfolgen automatisch
- Truncation: Wie Convertible - nur passt das Ergebnis nicht mehr in die Spalte hinein (und wird daher "beschnitten")
- Lossy: Hier sind noch immer falsche Zeichen enthalten, die im Verlauf der Konvertierung verloren gehen
Mit etwas Glück gehören die meisten unserer Daten in die Kategorien 1 und 2, sowie möglichst wenige (am besten gar keine) in Kategorie 3. Kandidaten für Kategorie 4 sollten wir eigentlich bereits beseitigt haben – falls nicht, zurück zum entsprechenden Abschnitt und richtig aufräumen.
Die Kandidaten der dritten Kategorie benötigen ein wenig extra Aufmerksamkeit.
Hier müssen wir unsere Tabellen-Definitionen prüfen und ggf. nachbessern, d. h.
die entsprechenden Spalten in der Größe derart anpassen, dass unsere Daten
wieder hineinpassen. Sollte dies nicht möglich sein, passen wir die
entsprechenden Datensätze besser von Hand an – damit der Inhalt verständlich
bleibt. Das ist jedoch nur bei VARCHAR2 Feldern nötig, deren Inhalt in Folge
der Konvertierung mehr als 4.000 Bytes umfasst (einige Sonderzeichen benötigen
in UTF8 mehr als ein Byte). Keine Sorge also bei Datensätzen, deren Felder
z. B. vom Typ VARCHAR(50) sind: CSScan sieht hier nur die aktuelle
Spaltendefinition (die, ausgeschrieben, VARCHAR(50 BYTE) lautet). Wir ändern
später die Semantik derart, dass die Spalte vom Typ VARCHAR2(50 CHAR) ist.
Das ändert allerdings nichts daran, dass VARCHAR2 generell auf maximal 4.000
Byte limitiert ist – doch diese sprengen wir nicht mit einem VARCHAR2(50).
"Gefährlich" wird es hier erst ab ca. VARCHAR2(2000), wenn der Inhalt nur aus
Sonderzeichen besteht …
Vorbereitung der Datenbank-Strukturen
In der Regel müssen wir für die Migration eine neue Datenbank aufsetzen, die
von Anfang an gleich mit dem Zeichensatz AL32UTF8 angelegt wird. Die Fälle,
in denen ein einfaches ALTER DATABASE CHARACTER SET AL32UTF8 genügt, sind
ziemlich rar. Es gilt also folgendes Rezept:
- Man nehme die Skripte, die zur Erstellung der gegenwärtigen Datenbank
verwendet wurden (oder äquivalente Skripte), und lege sich davon eine Kopie
an. Diese editiert man hinsichtlich ihres Zeichensatzes sowie ggf. des
Datenbanknamens (es können keine zwei Datenbanken mit dem gleichen Namen
gleichzeitig auf dem selben Rechner laufen – bei Verwendung unterschiedlicher
Rechner kann der Name – die
ORACLE_SID– natürlich beibehalten werden). Natürlich kann hierfür auch der DBCA verwendet werden. - Die Skripte sind nun auszuführen, um die neue Datenbank zu erstellen (auf
jeden Fall darauf achten, dass zuvor die Umgebungsvariable
NLS_LENGTH_SEMANTICS=CHARgesetzt wurde). - Nun wird von der ursprünglichen Datenbank ein "full export" mit dem Parameter
ROWS=Nerstellt – womit lediglich alle Strukturen, jedoch keine Daten exportiert werden. Kein Problem also selbst im 24/7 Betrieb. - Aus dem so entstandenen Export importieren wir nun lediglich die Schemata,
die wir migrieren wollen – aber z. B. keinesfalls die Schemata
SYS,SYSTEM, etc. (also Oracle-eigene System-Schemata).
Wie die gerade genannten 4 Schritte umzusetzen sind, sollte jeder DBA wissen; daher gehe ich da jetzt nicht ins Detail – sondern konzentriere mich auf das Wesentliche ;)
NLS Length Semantics
Wenn nicht explizit anders vorgegeben, ist der Parameter NLS_LENGTH_SEMANTICS
auf BYTE eingestellt. Im Klartext heißt dies: Wird eine Spalte als
VARCHAR2(50) definiert, übersetzt Oracle dies als VARCHAR2(50 BYTES). Aber
was hat dies für Folgen? Für unsere Latin-15 Datenbank eigentlich gar keine: Da
jedes Zeichen hier genau ein Byte belegt, sind die Semantiken BYTE und CHAR
hier gleichbedeutend. Bei UTF8 sieht das jedoch anders aus, da hier manche
Zeichen mehr als nur 1 Byte belegen. Ist die Semantik also hier auf BYTE
gesetzt, lässt sich nicht sagen, wie viele Zeichen hier "per se" in ein
VARCHAR2(50) passen. Oder ob all unsere VARCHAR2(50) Felder sich problemlos
konvertieren lassen.
Um dieses Problem (weitgehend) zu vermeiden, setzen wir explizit
NLS_LENGTH_SEMANTICS=CHAR. Somit interpretiert Oracle unsere
obige Definition auch als VARCHAR2(50 CHAR) – und wir wissen, dass
in jedem Fall genau 50 Zeichen hier hinein passen – auch wenn sie mehr
Bytes benötigen. Die Beschränkung auf 4.000 Zeichen lässt sich damit
natürlich nicht umgehen – wie viele Zeichen also in ein VARCHAR2(4000 CHAR)
Feld passen, hängt von den verwendeten Zeichen ab.
Semantik Konvertierungen
Jetzt haben wir also die NLS_LENGTH_SEMANTICS explizit auf BYTE gesetzt,
unsere UTF8 Datenbank angelegt, und die Strukturen importiert. Man könnte also
denken, dass wir jetzt einfach die Daten nachziehen können. Leider falsch:
Oracle hat die Strukturen so importiert, wie sie ursprünglich angelegt wurden –
also auch mit der derzeitigen Semantik. Was ja durchaus seine Berechtigung hat
…
… uns aber mit einer weiteren Aufgabe konfrontiert: Wir müssen nun für all unsere Tabellen die Semantiken anpassen. Zum Glück haben wir dafür ein passendes Skript zur Hand, um nicht alles manuell machen zu müssen. Nein, das Skript wird nicht von Oracle bereitgestellt – Zeit also, endlich mein IZ_MIGRATION Package vorzustellen, was u. a. die hierfür benötigte Prozedur bereitstellt. Das Package steht unter der GPL, kann also kostenlos bezogen werden. Näheres dazu findet sich hier auf IzzySoft.DE.
Und die genannte Prozedur ist iz_migration.semantics2char() (Details finden
sich in der Dokumentation des Packages). Wer ebenfalls alle Felder mit
"national character set" (NCHAR, NVARCHAR) in ihre "normalen Pendants"
(CHAR,VARCHAR2) umwandeln möchte, findet auch dafür die passende Prozedur
im Package.
Truncation
Als wir die zu konvertierenden Zeichen und das Tool CSScan
behandelten, kamen wir auch auf die Kategorie Truncation zu sprechen: Fälle,
in denen die konvertierten Inhalte "beschnitten" werden müssen, um noch in das
Feld zu passen. Wer diese Aufgabe auf "später" verschieben möchte, findet
sicher an der Prozedur iz_migration.truncate_long_fields() Gefallen: Sie
schneidet nur das ab, was wirklich weg muss – speichert jedoch den
ursprünglichen Inhalt in einem CLOB Feld einer speziellen Tabelle, zusammen
mit dem Namen des Objektes und der zugehörigen RowID, sodass man sie später
einfach wieder auffinden kann. Die Felder müssen auf jeden Fall vor dem Import
"gekürzt" werden – da die entprechenden Zeilen sonst nicht importiert werden
können. Die gerade genannte Weise erlaubt ein automatisches Kürzen, wobei man
sich um evtl. notwendige Korrekturen später kümmern kann.
Datentransfer: Vergleich verschiedener Strategien
Drei mögliche Strategien kommen für die Datenmigration in Betracht. Folgende Tabelle soll eine kurze Übersicht geben, bevor wir diese Strategien im Detail betrachten:
| Strategie | Pros | Cons |
|---|---|---|
ALTER DATABASE |
Schnell und sicher | Nur in sehr seltenen Fällen anwendbar |
| EXP/IMP | Sicher und von Oracle unterstützt | Langsam, benötigt eine relativ große Downtime |
| DBLink Copy | Relativ kurze Downtime | Nicht (offiziell) von Oracle unterstützt, evtl. nicht ganz "Error-proof" |
Die ALTER DATABASE Methode
Sofern anwendbar, ist dies natürlich die erste Wahl: Von allen genannten Methoden ist sie nicht nur die schnellste ((fast gar) keine Downtime), sondern auch noch die sicherste und von Oracle voll unterstützt. Klingt soweit echt super – muss also einen Haken haben. Und hier kommt er: Nicht auf eine Latin-15 Datenbank anwendbar. Fällt also für unser Beispiel flach.
Export/Import
Was also empfiehlt Oracle für unseren Fall? Genau: Erstellen eines kompletten, konsistenten Datenbank Export, der anschließend in die (neu erstellte) UTF8 Datenbank importiert wird. Vom Prinzip her. Details dazu finden sich auf allen Oracle Seiten, daher brauchen wir hier nicht ins Detail zu gehen. Der Haken ist recht offensichtlich: Für einen kompletten und konsistenten Export muss die Datenbank ein Weilchen geschlossen werden. Und da in der Zeit zwischen dem Export und dem Öffnen der neuen Datenbank wohl kaum Änderungen am Inhalt erwünscht sein dürften, muss auch die alte Datenbank während des Imports in die neue Datenbank geschlossen bleiben. Abhängig von der Größe der Datenbank, kann dies schon Mal einen ganzen Tag (oder auch mehr) bedeuten.
Die DBLink Methode
Nicht immer ist es möglich, für einen ganzen (Arbeits-) Tag auf die Datenbank zu verzichten. Oftmals nicht einmal dann, wenn zumindest noch ein Nur-Lesen Zugriff möglich ist (was ja generell machbar wäre). Also brauchen wir eine Alternative. Es mag vielleicht überraschend klingen: Aber es geht sehr viel schneller, eine Tabelle über einen Datenbank-Link zu kopieren, als das Kopieren über Export/Import. Das Ergebnis dieser "Entdeckung" war das IZ_MIGRATION Package.
Die dahinter stehende Idee ist recht einfach: Da wir bereits die gesamte
Struktur in der neuen Datenbank vorliegen haben, brauchen wir nur durch das
Database Dictionary zu wandern nach dem Motto "Für jedes Schema – für jede
Tabelle – INSERT INTO schema.tabelle SELECT * FROM schema.tabelle@dblink.
Natürlich ist dabei noch einiges mehr zu beachten – was in der Dokumentation
des Packages auch näher erklärt wird. Insbesondere:
- Um den Kopierprozess zu beschleunigen (und Datenkonsistenz zu gewährleisten sowie Constraint Violations zu vermeiden), schalten wir zuerst alle Trigger und Constraints ab. Nach dem Kopieren aller Daten, aktivieren wir diese wieder
- Ebenfalls vor dem Import, löschen wir alle Indexe (mit wenigen Ausnahmen
wie z.B.
PRIMARY KEYundUNIQUEIndexes, die wir zur Sicherstellung der Konsistenz beibehalten) – und erstellen sie nach erfolgtem Datenimport neu. Das beschleunigt den Kopierprozess, und sorgt quasi als Nebeneffekt auch noch für saubere, gut balancierte Indexe - Um Sequences muss sich gesondert gekümmert werden
Für Constraints, Trigger und Sequences enthält das Package natürlich die
benötigten Prozeduren. Dabei werden – um die Datenbank möglichst schnell wieder
verfügbar zu haben – die Constraints im Anschluss an den Kopiervorgang
lediglich unvalidiert aktiviert (ENABLE NOVALIDATE) – wir gehen zunächst
davon aus, dass die Daten vorher auch "valid" waren und müssen nur
sicherstellen, dass nichts "invalides" hinzukommt. Nachdem die Datenbank wieder
verfügbar ist, kann (und sollte) eine separate Prozedur dazu verwendet werden,
sich (z. B. in einem nächtlichen Job) um die Validierung zu kümmern.
Auch um das Löschen der Indexe kann sich das Package kümmern. Zuvor sollten die Definitionen dieser Indexe jedoch gesichert werden, damit sie später wieder angelegt werden können – ein Skript, was genau dieses tut, findet sich am Ende dieser Seite.
Noch eine Warnung bzgl. der DBLink Copy Methode
Wie bereits eingangs erwähnt, wird diese Methode von Oracle weder "supported" noch gar empfohlen. Was vielleicht noch schlimmer ist: Sie wurde bislang auch keinem großen Test unterzogen (jaja, das Übliche: Wann bekommt man als Entwickler schonmal Feedback? Eigentlich nur, wenn jemand auf Probleme gestoßen ist). Zwar habe ich diese Methode (und natürlich das IZ_MIGRATION Package) erfolgreich bei einigen Migrationen eingesetzt (und dabei noch die eine oder andere Kleinigkeit korrigiert) – doch kann man daraus nicht auf eine Empfehlung zur Migration jedweder Produktions- Datenbank schließen. Wer es also aufgrund der damit verbundenen wesentlich kürzeren Downtime einsetzen, dabei aber die Risiken möglichst gering halten möchte, engagiert am besten den Entwickler selbst (also mich) für dieses Projekt. Auf jeden Fall sollte die ganze Migration zunächst anhand einer Testumgebung, die dem Produktivsystem so ähnlich wie möglich ist, getestet werden.
Skript zum Erstellen der CREATE INDEX Statements
-- Retrieving all index information (create-script) for non-pk and non-unique indexes SET SERVEROUTPUT ON FEEDBACK OFF SPOOL create_indexes.sql DECLARE town VARCHAR2(40) := '0'; CURSOR cur IS SELECT i.owner,i.index_name FROM dba_indexes i,dba_constraints c WHERE i.owner = c.owner(+) AND i.index_name = c.index_name(+) AND c.index_name IS NULL AND i.index_type NOT LIKE 'IOT%' AND i.index_type != 'LOB' AND i.owner NOT IN ('SYS','SYSTEM','CSMIG','CTXSYS','DBSNMP','DMSYS','EXFSYS', 'HR','IX','MDSYS','OE','OLAPSYS','ORDSYS','OUTLN', 'SH','SYSMAN','WKSYS','WK_TEST','WMSYS','XDB') ORDER BY i.owner,i.index_name; PROCEDURE print(line IN VARCHAR2) IS -- wrapper to dbms_output.put_line - work around the 255 characters limit pos NUMBER; FUNCTION strpos (str IN VARCHAR2,needle IN VARCHAR2,startpos NUMBER) RETURN NUMBER IS -- split string helper to procedure print pos NUMBER; strsub VARCHAR2(255); BEGIN strsub := SUBSTR(str,1,255); pos := INSTR(strsub,needle,startpos); return pos; END; BEGIN dbms_output.put_line(line); EXCEPTION WHEN OTHERS THEN IF SQLERRM LIKE '%ORU-10028%' THEN pos := strpos(line,' ',-1); print(SUBSTR(line,1,pos)); pos := pos +1; print(SUBSTR(line,pos)); ELSE dbms_output.put_line('-- *!* Problem in print() *!*'); END IF; END; BEGIN dbms_output.enable(1000000); FOR rec IN cur LOOP IF town != rec.owner THEN town := rec.owner; print('-- ===============================[ Schema '||town||' ]==='); END IF; print(dbms_metadata.get_ddl('INDEX',rec.index_name,rec.owner)||';'); END LOOP; END; / SPOOL OFF |
Fazit
Für die Migration einer Oracle-Datenbank stehen verschiedene Strategien zur Verfügung – von "sehr sicher" bis "sicher, aber schneller". Wir haben uns das im Detail angesehen. Viele Schritte in der Vorbereitungen sind zudem bei allen betrachteten Methoden identisch.
Welche Strategie nun auch zum Einsatz kommt: Das IZ_MIGRATION Package kann bei der Migration hilfreich sein, und die Lösung einiger Aufgaben wesentlich erleichtern. Auf IzzySoft.DE finden sich mehr Details – sowie eine Möglichkeit zum Download dieser und weiterer (Oracle-) Software.

Das Inoffizielle Android-Handbuch
Das Inoffizielle Android Systemhandbuch
Die besten Android-Apps