Migrieren einer Oracle XE 10-Installation nach Oracle XE 11 unter Windows

Oracle XE, die kostenlose Express-Version, ist aus meiner Sicht im Vergleich zum SQL Server von Microsoft deutlich „spröder“ in der Bedienung.

Z. B. kann ich nicht einfach eine Version 10 auf Version 11 per Setup updaten.

Stattdessen muss mit der Verwendung von Befehlszeilen-Programmen ein Export erstellt werden und anschließend ein Import.

Nachfolgend habe ich die Schritte aufgeschrieben.

(Es gibt auch eine offizielle Kurzanleitung von Oracle)

Randbedingungen

  • Quellsystem und Zielsystem sind unterschiedliche Rechner.
  • Ordnerstruktur Quellsystem und Zielsystem sind ähnlich/identisch.

Export vom Quellsystem

SQL Plus starten:

C:\oraclexe\app\oracle\product\10.2.0\server\BIN\sqlplus.exe system/meinkennwort@XE

Und dann einen Export-Ordner anlegen als Alias auf einen tatsächlichen:

CREATE DIRECTORY migr_xe_to_11 AS 'C:\Ablage';

Dann SQL Plus wieder beenden:

EXIT

Mit dem Expdp-Programm den Export anstoßen:

C:\oraclexe\app\oracle\product\10.2.0\server\BIN\expdp.exe system/meinkennwort@XE DIRECTORY=migr_xe_to_11 DUMPFILE=migr_xe%U FILESIZE=500MB LOGFILE=migr_xe_to_11.log FULL=Y

Es werden dann eine oder mehrere DMP-Dateien angelegt. In meinem Fall waren es:

  • C:\ABLAGE\MIGR_XE01.DMP
  • C:\ABLAGE\MIGR_XE02.DMP
  • C:\ABLAGE\MIGR_XE03.DMP

Diese Dateien jetzt auf das Zielsystem kopieren.

Import im Zielsystem

SQL Plus starten:

C:\oraclexe\app\oracle\product\11.2.0\server\bin\sqlplus.exe system/meinkennwort@XE

Ordner anlegen:

CREATE DIRECTORY migr_xe_to_11 AS 'C:\Ablage';

SQL Plus wieder beenden:

EXIT

Jetzt mit dem Impdp-Programm die DMP-Dateien importieren:

C:\oraclexe\app\oracle\product\11.2.0\server\bin\impdp.exe system/meinkennwort@XE DIRECTORY=migr_xe_to_11 DUMPFILE=migr_xe%U LOGFILE=imp_xe_to_11.log

Fehlerlokalisierung Import

Bei mir hat der Import teilweise funktioniert, teilweise kamen Fehlermeldungen à la:

ORA-02374: conversion error loading table „UKEIM“.„SHADOW_STEWII_AUD“
ORA-12899: value too large for column ZUORD (actual: 7, maximum: 6)
ORA-02372: data for row: ZUORD : 0X’34313554DC31’

Um das herauszubekommen, habe ich folgenden Befehl in SQL Plus ausgeführt:

SELECT * FROM NLS_DATABASE_PARAMETERS;

Und zwar auf dem Quell- und Zielsystem.

Außerdem haben wir auf dem Zielsystem noch den Befehl

show parameters pool;

und den Befehl

show parameters buffer;

ausgeführt.

Das hat die Ursache aufgezeigt: der Fehler war, dass das Encoding (Wert von NLS_CHARACTERSET) der Quelldatenbank „WE8MSWIN1252“ war und das Encoding der Zieldatenbank „AL32UTF8“.

Dadurch wurden wohl Feldinhalte aufgebläht und haben die maximale Feldgröße überschritten.

Fehlerbehebung

Wir haben das dann wie folgt behoben:

  1. Auf Quelldatenbank wurden in allen Tabellen in allen Text-Spalten die maximalen Größen erhöht. Siehe nachfolgende Stored Procedure.
  2. Danach nochmals neu exportiert.
  3. Anschließend erneut importiert.

Nun hat bei mir der Import funktioniert.

create or replace PROCEDURE INCREASE_VARCHAR_1_5 AS 
V_NEW_LENGTH NUMBER; 
BEGIN
  FOR V_TABLE IN (SELECT * FROM USER_TABLES) LOOP
      
      FOR V_COLUMN IN (SELECT * FROM ALL_TAB_COLUMNS WHERE TABLE_NAME = V_TABLE.TABLE_NAME AND DATA_TYPE LIKE '%VARCHAR%') LOOP
        V_NEW_LENGTH := CEIL(V_COLUMN.DATA_LENGTH * 1.5);
        
        IF V_COLUMN.DATA_TYPE LIKE 'NVARCHAR%' THEN
          IF V_NEW_LENGTH > 2000 THEN
            V_NEW_LENGTH := 2000;
          END IF;
        ELSE
          IF V_NEW_LENGTH > 4000 THEN
            V_NEW_LENGTH := 4000;
          END IF;
        END IF;
        
        IF V_COLUMN.DATA_TYPE LIKE 'NVARCHAR%' THEN
          V_NEW_LENGTH := V_COLUMN.CHAR_LENGTH;
          --NVARCHAR ist immer CHAR https://community.oracle.com/thread/837666?start=0&tstart=0
          EXECUTE IMMEDIATE 'ALTER TABLE "' || V_TABLE_NAME || '" MODIFY ("' || V_COLUMN_NAME || '" ' || V_COLUMN.DATA_TYPE || '(' || V_NEW_LENGTH || '))';
        ELSE
          V_NEW_LENGTH := V_COLUMN.DATA_LENGTH;
          EXECUTE IMMEDIATE 'ALTER TABLE "' || V_TABLE_NAME || '" MODIFY ("' || V_COLUMN_NAME || '" ' || V_COLUMN.DATA_TYPE || '(' || V_NEW_LENGTH || ' CHAR))';
        END IF;
      END LOOP;
  END LOOP;
END INCREASE_VARCHAR_1_5;

Offene Punkte

Ich konnte noch nicht testen, ob das geänderte Encoding sich negativ auf Umlaute usw. auswirkt.

Eventuell sind in der Zieldatenbank die Umlaute kaputt.

In meinem Fall macht mir das nichts aus, weil es eh nur Testdaten sind.

Theoretisch bessere Fehlerbehebung

Eigentlich hätten wir das Encoding der Zieldatenbank ändern sollen, so dass es dem der Quelldatenbank entspricht.

Alternativ hätte ich auch eine neue Zieldatenbank anlegen können.

Ersteres war mir zu kompliziert, der inoffizielle Weg hat mir Fehler geworfen, der offizielle Weg mit irgendwelchen SQL-Skripten habe ich nicht kapiert.

Eine neue Zieldatenbank konnte ich auch nicht anlegen, weil in der Express-Edition (XE) von Oracle das „dbca“-Tool zum Erstellen neuer Datenbanken nicht vorhanden ist.

Und beim Installieren von XE habe ich keine Möglichkeit gefunden, das Encoding anzugeben.

Abschließende Gedanken

Ich habe den Import zunächst nicht auf meinem tatsächlichen Zielsystem getestet, sondern in einer VMware-Maschine.

Erst danach habe ich auf dem System, auf dem Oracle XE 10 lief, dieses deinstalliert (vorher Export, logisch) und dann Oracle XE 11 installiert und dann dort importiert.

Um übrigens schöner formatierte Ausgaben in SQL Plus zu bekommen, die Befehle

set pagesize 50000;

und

set linesize 120;

innerhalb von SQL Plus ausführen.

Tipp von hier.

Oracle 11 nach Oracle 21c

Habe Daten von einer Oracle-XE-Instanz unter Windows auf ein neu aufgesetztes Oracle-XE unter Ubuntu-Linux mit Docker migriert.

Also das Oracle läuft als Docker-Container:

docker run --name OracleZeta -d --restart=always -p 1521:1521 -p 5500:5500 -e ORACLE_PWD=HereComesAPassword -v ZetaOracleVolume:/opt/oracle/oradata container-registry.oracle.com/database/express:21.3.0-xe

(Bitte auch via sudo systemctl enable docker sicherstellen, dass Docker beim Systemstart läuft).

Ich habe dazu zunächst alle Benutzer/Schemas via „sqlplus“-Befehlszeilenprogramm auf der Zieldatenbank angelegt.

„sqlplus“ habe ich von einem Windows-Client aus gestartet und mich mit der Oracle XE in Docker verbunden:

„C:\Ablage\sqlplus.exe“ sys/HereComesAPassword@//MyServer/XE as sysdba

Anschließend dann die User anlegen, die Berechtigungen vergeben, und darauf geachtet, zuvor alter session set "_ORACLE_SCRIPT"=true; ausgeführt zu haben.

Die Migration der Daten habe ich dann via Oracle SQL Developer und der Funktion „Extras“ > „Datenbankkopie“ gemacht:

Dort konnte ich eine Quellverbindung zur bestehenden, alten Oracle-XE-Instanz auswählen, und anschließend eine Zielverbindung zur neuen Oracle-XE-Instanz unter Ubuntu, und anschließend konfigurieren, dass ich DDL und Daten migrieren möchte.

Das lief eigentlich recht gut durch. Traten Fehler auf, habe ich jeweils die Option (sinngemäß) „Fehler ignorieren und Verarbeitung fortsetzen“ ausgewählt).

Da es Foreign-Key-Fehler gab, und ich annahm, dass das aufgrund falscher Reihenfolge der Tabellen auftrat, habe ich einfach den „Datenbankkopie“-Assistenten mehrfach gestartet. Beim zweiten Mal dann nur noch die Daten, nicht mehr die DDL.

Oracle 11 nach Oracle 21c

Mist, die Lösung über den Export-Wizard war doch nicht so der Bringer (Daten unvollständig), ich habe nochmals den Data Pump laufen lassen, nur mit Daten:

expdp.exe UKEIM/MeinKennwort@MeinQuellServer:1521/XE DIRECTORY=migr DUMPFILE=migr.dmp LOGFILE=migr.log schemas=UKEIM

Das dann per scp auf den Linux-Server nach /var/tmp kopiert:

scp c:\Ablage\MIGR.DMP administrator@MeinZielServer:/var/tmp/

Und anschließend per SSH auf den Linux-Server gegangen und von dort per docker cp in den Oracle-Docker-Container nach /var/tmp kopiert:

docker cp /var/tmp/MIGR.DMP MeinContainerName:/var/tmp/MIGR.DMP

Dann alle Tabellen gelöscht.

Und anschließend den Import laufen lassen:

impdp.exe UKEIM/MeinKennwort@MeinZielServer:1521/XE DIRECTORY=migr DUMPFILE=MIGR.DMP LOGFILE=migr.log schemas=UKEIM

Leider fehlen auch hier jetzt immer noch Daten (Import teilweise mit Constraint-Violation-Fehlern fehlgeschlagen), ggf. lasse ich das ganze nochmals laufen, komplett mit Schema und so.