In der Vergangenheit habe ich oft Projekte geleitet, bei der es um die Migration von Oracle Datenbanken ging. Vor allen Dingen Migrationen nach Linux, vereinzelt Migrationen in Richtung Standard Edition und immer wieder auch eine Zeichensatz Konvertierung Richtung Unicode.
In der Regel erfolgte diese Migration durch einen Neuaufbau der Zieldatenbank und anschließendem Export – Import der Daten. Dabei hat mir Quest SharePlex immer sehr geholfen, da durch die Replikation der Änderungen die Downtime für die Migration auf wenige Minuten (in der Regel der Dauer für die Umschaltung der Anwendung) beschränkt werden konnte.
Für die reine Zeichensatzkonvertierung bietet Oracle allerdings auch die Prozedur CSALTER an, also warum sollte man noch eine neue Datenbank aufbauen, wenn es doch so leicht ist, den Zeichensatz zu ändern.
Das Beispiel habe ich mit einer Oracle 11g (11.2.0.2) Datenbank auf Linux (wie bei mir üblich OEL 6) ausgeführt.
CSSCAN
Zunächst muss man die Datenbank einmal durchscannen, um eventuelle Problemfälle zu lokalisieren. Hierfür muss zunächst mit der Prozedur csminst.sql (im Verzeichnis $ORACLE_HOME/rdbms/admin) das Schema csmig angelegt werden.
Danach kann der Befehl csscan mit entsprechenden Parametern oder Interaktiv aufgerufen werden.
% csscan Character Set Scanner v2.2 : Release 11.2.0.2.0 - Production on Tue Feb 21 16:06:32 2012 Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved. Username: sys as sysdba Password: Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production With the Partitioning, OLAP, Data Mining and Real Application Testing options (1)Full database, (2)User, (3)Table, (4)Column: 1 > Current database character set is WE8ISO8859P15. Enter new database character set name: > AL32UTF8 Enter array fetch buffer size: 1024000 > Enter number of scan processes to utilize(1..64): 1 > Enumerating tables to scan... . process 1 scanning SYS.SOURCE$[AAAADgAABAAAAXgAAA] ... Creating Database Scan Summary Report... Creating Individual Exception Report... Scanner terminated successfully.
In der Datei scan.txt findet man jetzt einige Details zum Scan. Wichtiger ist jedoch die Datei scan.err, denn hier werden die Fehler beim Scan angezeigt, also Felder oder Datentypen, bei denen die Konvertierung nicht funktioniert bzw. bei der z.B. Zeichen abgeschnitten werden. In meinem Fall sieht diese Datei so aus:
Database Scan Individual Exception Report [Database Scan Parameters] Parameter Value ------------------------------ ------------------------------- CSSCAN Version v2.1 Instance Name VMLIN11A Database Version 11.2.0.2.0 Scan type Full database Scan CHAR data? YES Database character set WE8ISO8859P15 FROMCHAR WE8ISO8859P15 TOCHAR AL32UTF8 Scan NCHAR data? NO Array fetch buffer size 1024000 Number of processes 1 Capture convertible data? NO ------------------------------ ------------------------------ [Data Dictionary individual exceptions] User : SYS Table : SOURCE$ Column: SOURCE Type : VARCHAR2(4000) Number of Exceptions : 0 Max Post Conversion Data Size: 4000 ROWID Exception Type Size Cell Data(first 30 bytes) ------------------ ------------ ----- ------------------------------ AAAADgAABAAAJwOAAN convertible -- 1. Prozedur, um die Kunde AAAADgAABAAAJwOACg convertible -- Sequence muss in Variable AAAADgAABAAAJwOACn convertible -- Füllen der Tabelle Persone AAAADgAABAAAJwPAB3 convertible -- 2. Prozedur, um die Auftr AAAADgAABAAAJwQAAT convertible -- Wenn die Positionentabelle AAAADgAABAAAJwQAAU convertible -- den Produkterecord hier zu AAAADgAABAAAJwQABW convertible --- Nur für Auftraege, di AAAADgAABAAAJwRAAL convertible -- 3. Prozedur, um die Posit AAAADgAABAAAJwRAAq convertible -- direkt gefüllt wird, anson ------------------ ------------------ ----- ------------------------- [Application data individual exceptions] User : DEMO Table : STATUS Column: STATUSID Type : CHAR(1) Number of Exceptions : 1 Max Post Conversion Data Size: 2 ROWID Exception Type Size Cell Data(first 30 bytes) ------------------ ------------------ ----- ------------------------- AAAEZmAAEAAAAEcAAA exceed column size 2 Ü ------------------ ------------------ ----- -------------------------
Okay, mit den deutschen Kommentaren in den PL/SQL Routinen komme ich klar. Wichtiger ist die letzte Zeile, denn in der Tabelle STATUS des Schemas DEMO gibt es das Feld STATUSID als CHAR(1). Die Konvertierung in AL32UTF8 benötigt für das “Ü” zwei Zeichen, das Feld ist jedoch als CHAR(1) (also 1 BYTE) definiert. Dieser Fehler muss erst behoben werden, bevor die Konvertierung weiterlaufen kann.
Okay: also zunächst die Tabelle anpassen (z.B: aus dem “Ü” ein “U” machen) und die PL/SQL Prozeduren löschen – hat man ja sowieso als Source vorliegen – oder?
Jetzt ein neuer Scan (hier als Befehl mit den Parametern):
% csscan \"sys/manager as sysdba\" FULL=Y TOCHAR=AL32UTF8 LOG=utftest ARRAY=1000000 PROCESS=1 % more utftest.errDatabase Scan Individual Exception Report [Database Scan Parameters] Parameter Value ------------------------------ ------------------------------------- CSSCAN Version v2.1 Instance Name VMLIN11A Database Version 11.2.0.2.0 Scan type Full database Scan CHAR data? YES Database character set WE8ISO8859P15 FROMCHAR WE8ISO8859P15 TOCHAR AL32UTF8 Scan NCHAR data? NO Array fetch buffer size 1000000 Number of processes 1 Capture convertible data? NO ------------------------------ ------------------------------------- [Data Dictionary individual exceptions] [Application data individual exceptions]
Hurra, kein Fehler, also steht der Konvertierung auf AL32UTF8 nichts mehr im Wege.
CSALTER
Hierbei handelt es sich um eine Prozedur, die im Verzeichnis $ORACLE_HOME/rdbms/admin steht (csalter.plb). Die Prozedur holt sich alle Informationen aus den Tabellen des Schemas CSMIG. D.h. vorher muss der Befehl csscan aufgerufen worden sein und dieser Scan darf nicht älter als 7 Tage sein.
% sqlplus / as sysdba SQL> @?/rdbms/admin/csalter.plb 0 rows created. Function created. Function created. Procedure created. This script will update the content of the Oracle Data Dictionary. Please ensure you have a full backup before initiating this procedure. Would you like to proceed (Y/N)?y old 6: if (UPPER('&conf') <> 'Y') then new 6: if (UPPER('y') <> 'Y') then Checking data validity... Sorry only one session is allowed to run this script PL/SQL procedure successfully completed. Checking or Converting phase did not finish successfully No database (national) character set will be altered CSALTER finished unsuccessfully. PL/SQL procedure successfully completed. 0 rows deleted. Function dropped. Function dropped. Procedure dropped.
Okay: erster Fehler: für den Aufruf von csalter darf kein anderen Benutzer mehr an der Datenbank angemeldet sein “Sorry only one session is allowed to run this script“. Also Datenbank herunterfahren und im Restricted Mode starten.
Danach wieder der gleiche Aufruf…
Ich erspare mir hier die Ausgabe, da ich es nicht hinbekommen habe, die Zeichensatzkonvertierung erfolgreich zum Abschluss zu bringen. Der Grund ist, dass csalter nur eine Konvertierung des Data Dictionaries durchführt und nicht der Inhalte von Tabellen. Da sich in meiner Datenbank aber “merkwürdigerweise” Daten mit Sonderzeichen (z.B. Umlaute) befinden, schlägt die Konvertierung fehl mit der Meldung: “Unrecognized convertible data found in scanner result“.
Erst nachdem ich die Schema mit den Daten gelöscht hatte, war eine Konvertierung möglich – aber wer braucht das schon.
An dieser Stelle wäre ich sehr an einer Diskussion interessiert. Vielleicht war ja jemand erfolgreicher als ich. Für mich gilt jedoch weiterhin: bei einer Migration eine neue Datenbank aufzubauen und die Daten per Export / Import (ob DataPump oder wie auch immer) zu übertragen. In meinem nächsten Blog werde ich aber noch einmal auf das Thema Umlaute bei UTF8 und maximale Anzahl von Zeichen zu sprechen kommen.