Datenbankmigration nach Unicode

, ,

cpi-partner-kyrill-schnitt

Einer unserer Kunden ist in der Güterbeförderung auf der Schiene im europäischen Raum tätig. Die Anwendung, mit dem die Abrechnung der Transporte gesteuert wird, basiert auf Oracle Forms und der Oracle Datenbank 11gR2. Dieses System weist sehr viele Schnittstellen unterschiedlichster Natur auf: zum Host, auf dem die Schienenbewegungen erfasst werden, zu einem anderen, ebenfalls Oracle-Forms-basierten System, in dem die Auftraege gesteuert werden, zu SAP, zur Bank und zum Druckdienstleister, der aus den aus der Datenbank geschriebenen XML-Dateien PDF-Dokumente erzeugt.

Im Rahmen der europäischen Integration bekommt das System Zuwachs. Die Bahnen aus osteuropäischen Laendern sollen angeschlossen werden. Dabei ergibt sich ein Problem: In diesen Ländern ist der kyrillische Zeichensatz weit verbreitet. Firmennamen, Ortsnamen, Strassennamen tragen kyrillische Bezeichnungen. Das System soll also in die Lage versetzt werden, neben west- auch osteuropäische Zeichen zu unterstützen. Also muss das gesamte System aus Datenbank, Forms-Server und eigenentwickelten Schnittstellen in Unicode migriert werden. Und da die Datenmengen ständig wachsen, sollte die Umstellung so bald wie möglich erfolgen.

Für neue Datenbank-Installationen ist Unicode, oder UTF-8, bereits seit längerer Zeit Standard. Auch bei Java und XML ist die Verwendung von Unicode längst üblich. Neue Oracle-Datenbank-Installationen werden vom Oracle Universal Installer als Default im Oracle-Zeichensatz AL32UTF8 (NCHAR AL32UTF16) angelegt. Dieser Zeichensatz wird auch als UTF-8 bezeichnet und sollte nicht mit dem Oracle-Zeichensatz UTF8 verwechselt werden. Bei Oracle’s UTF8, auch als CESU-8 bezeichnet, handelt es sich um einen Legacy-Zeichensatz, dessen Verwendung nicht mehr empfohlen wird. Er stammt noch auf den Anfangszeiten von Oracle’s Engagement in Unicode.

AL32UTF8 ist ein dynamischer Multibyte-Zeichensatz, der 1-4 Bytes pro abzubildendem Zeichen verwendet. Für ASCII-Zeichen wird 1 Byte, für europäische Zeichen und solche aus dem mittleren Osten werden in der Regel 2 Bytes, für asiatische Zeichen in der Regel 3 Bytes verwendet. AL32UTF8 entspricht der Unicode 4.0-Konvention.

Für neue erstellte Datenbanken hat Oracle also sinnvolle Default-Einstellungen gesetzt, aber was macht man mit bestehenden Datenbanken? Ältere, westeuropäische Oracle-Installation verwendet oft WE8ISO8859P15, das war auch hier der Fall.

Migrationspfade

Traditionell gibt es zwei Arten der Datenbankmigration nach Unicode:

  • Der Neuaufbau einer frischen Datenbank im neuen Zeichensatz mit anschliessendem Re-Import der Daten. Bei diesem Ansatz wird eine neue Datenbank parallel aufgebaut. Beim Importieren der Daten wird der Zeichensatz dann durch Data Pump konvertiert. Das hat zunächst den Vorteil, den Neuaufbau parallel zum laufenden Betrieb und ohne Zeitdruck durchführen zu können. Allerdings werden hierfür dann auch doppelte Ressourcen benötigt: Es braucht Platz für den Parallelbetrieb der neuen Datenbank. Die Anforderungen an die Downtime („Betra“ – Betriebsausfall) hängen stark vom Datenvolumen ab, denn auch mit Data Pump dauert das Ex- und Importieren abhängig von CPU- und Storage-Leistung lange – in diesem Fall zu lange, um in die maximal mögliche Downtime von zwei Tagen zu passen.
  • Die Migration mit den CSSCAN/CSALTER-Tools. Bei diesen Verfahren wird mit dem Oracle-Tool CSSCAN zunächst überprüft, welche Konflikte in den vorhandenen Daten vorhanden sind. Bestimmte Probleme mit den Ausgangsdaten müssen manuell oder durch Reimport gelöst werden. Diese Tools sind allerdings mittlerweile etwas in die Jahre gekommen und können kein komplexeren Probleme wie das Verlängern von Spaltenbreiten (s.u.) oder die Konvertierung von Data Dictionary Objekten lösen.

Darüberhinaus gibt es einige neuere Ansätze:

  • DMU. Das Thema Unicode-Migration scheint in der letzten Zeit an Aktualität gewonnen zu haben und Oracle hat sich zur Datenbank-Version 11 entschlossen, ein Java GUI Tool zu entwickeln, welches versucht, den gesamten Prozess in einem geführten Workflow abzubilden. Der „Database Assistant for Unicode“ scannt die Datenbank, bereitet die Ergebnisse in einer anschaulichen Übersicht auf, bietet zur Behebung von Qualitätsproblemen einen eigenen Dateneditor und führt abschliessend die Konvertierung und eine abschliessende Kontrolle durch.
  • Abgehängte Migration mit Streams. Hier wird die Datenbank zunächst geklont. Zwischen der Original-Datenbank und der Kopie wird dann eine Streams-Replikation eingerichtet. Ist diese fertig, wird sie wieder angehalten, und nun kann die Kopie in aller Ruhe mit DMU konvertiert werden. Abschliessend wird die Replikation wieder aktiviert, und die Änderungen, die sich in der Zwischenzeit auf der Originalseite angesammelt haben, können übertragen werden. Streams ist in der Lage, diese während der Übertragung nach Unicode zu konvertieren. Sind beide Datenbanken auf dem gleichen Stand, kann der Betrieb in einer sehr kurzen Auszeit auf die Kopie umgeschaltet werden. Diese Methode bietet gleich eine ganze Reihe von Vorteilen: Sie ist neben der kurzen Umschaltzeit beliebig wiederholbar. Zudem kann die konvertierte Datenbank beliebig intensiv getestet werden, bevor sie live geschaltet wird. Wird ein Fehler gefunden, kann der Prozess jederzeit neu begonnen werden.

dmu textlogo

Bei diesem Projekt kamen aus Ressourcengründen alle Verfahren, die den parallelen Aufbau vorsehen, nicht in Frage. Dennoch sollte die Migration in ein Zeitfenster von einem Wochenende passen. Nach einigen Tests zur Geschwindigkeit des Datenex- und Imports wurde schnell klar, dass die 800Gigabyte Daten kaum in diesem Zeitfenster importiert werden konnten – vom zusätzlich notwendigen Aufbau der Unicode-Datenbank ganz abgesehen. Denn im Zeitfenster eines Wochendes müssen am Sonntag vormittag alle Umbauarbeiten abgeschlossen sein, da ein Rückfall auf ein vollständiges Restore mittags beschlossen werden müsste, wenn dieser bis Montag morgen garantiert durchgeführt werden soll. Erste Tests müssten also bis Sonntag Mittag erfolgreich absolviert werden. Aus diesen Gründen kamen nur noch die Methoden CSSCAN und DMU in Frage.

Probleme mit den Ausgangsdaten

cpi_vorgefundene_zeichen

In der nächsten Phase wurde mit CSSCAN und DMU eine Bestandsaufnahme über die in der Ausgangs-Datenbank vorhandenen Daten erhoben. Dabei wurden verschiedene Kategorien vom Ausgangszeichen angetroffen:

  • Daten, die nicht konvertiert werden müssen. Hierbei handelt es sich um Zahlen oder Zeichen, die im Ausgangs- und Ziel-Zeichensatz identisch abgebildet werden. 98% der Daten fielen in diese Kategorie.
  • Daten, die konvertiert werden müssen und können. Dies betraf 1% der Daten, 235 Millionen Zellen. Diese „straighforward“-Konvertierung kann das DMU-Tool von sich aus vornehmen. Aus dieser Kategorie waren neben VARCHAR2 auch LONG und CLOB-Typen vorhanden.
  • Daten, die eine Anpassung der Feldlängen im Datenmodell erfordern („over column limit“). Diese Problematik resultiert daraus, dass Feldlängen in Zeichenlängen früher als Anzahl der verwendeten Bytes angegeben wurden. Unglücklicherweise ist dies immer noch der Default, wenn Tabellen in Oracle angelegt werden. Erst wenn die Umgebungsvariable „nls_length_semantics“ auf „char“ gesetzt wird, oder bei der Spaltendefinition explizit das Wort „CHAR“ angegeben wird, wird die Feldlänge, abhängig vom Datenbank-Zeichensatz, als Anzahl von Zeichen interpretiert. Als BYTE angelegte Spalten können bei einem Multibyte-Zeichensatz wie UTF-8 nicht die ursprünglich vorgesehene Anzahl an Zeichen aufnehmen. Die Spaltendefinitionen müssen daher geändert und die Spaltenlängen vergrößert werden.
  • Zeichenketten, die im Multibyte-Zeichensatz so lang werden, dass sie nicht mehr in ein VARCHAR2-Feld passen („over type limit“). Ein VARCHAR2-Feld kann mit maximal 4000 Byte definiert werden. Solche Daten müssen gesondert behandelt werden, zum Beispiel, indem das VARCHAR-Feld in ein CLOB umgewandelt wird, oder in dem der Inhalt auf zwei VARCHAR-Felder aufgeteilt wird. Solche Änderungen am Datenmodell erfordern natürlich in der Regel auch applikatorische Anpassungen.
  • Daten, die offensichtlich nicht im Datenbank-Zeichensatz vorliegen („invalid binary representation“). Der binäre Wert dieser Zeichen hat keine Entsprechung im Zeichensatz der Datenbank. Da der Ausgangszeichernsatz nicht festeht (der der Datenbank ist es offensichtlich nicht), kann auch keine sinnvolle Konvertierung vorgenommen werden. Diese Daten sind aber auch vor der Konverung schon fehlerhaft: garbage in, garbage out. Wie diese Daten in die Datenbank gekommen sind, lässt sich oft nicht mehr festellen. Meist dürfte es an einem falsch konfigurierten Datenbank-Client liegen, dessen NLS_LANG-Konfiguration nicht der aktuellen Einstellung des Client-Betriebssystems oder dem Aufbau einer Import-Datei entspricht.

Sonderzeichen im Data Dictionary

Ein weiteres Problem für die Konvertierung sind Sonderzeichen im Data Dictionary. Diese kann der DMU nur in einigen Fällen konvertieren. In diesem Fall sorgten insbesondere Umlaute in Triggern und PL/SQL Packages für Probleme.

Eine Möglichkeit, damit umzugehen, ist, diese Objekte einzeln zu überarbeiten und entsprechende Sonderzeichen zu entfernen. Bei umfangreicher installierter Software ist dies allerdings meist nicht möglich. Andere Alternativen sind, diese Objekt zu ex- und nach der Migration wieder zu re-importieren, oder die Software zu löschen und neu zu installieren.

Ablauf der Migration

Das Projekt gliederte sich in drei Phasen: Bestandsaufnahme, Bereinigung und Konvertierung.

Bestandsaufnahme

dbpropscane

Für die Bestandsaufnahme erfolgte zunächst ein Scan mit dem DMU. Dazu muss zunächst die DMU-Software installiert werden. Jeder Computer mit Verbindung zur Datenbank kommt dafür in Frage, da die Java-Software des DMU prinzipiell unter jedem System mit Java JDK1.6 läuft. Auch in der Datenbank muss ein Package installiert werden: SYS.DBMS_DUMA_INTERNAL. Dies geschieht durch Einspielen des Skriptes ?/rdbms/admin/prvtdumi.plb. Die Datenbank sollte möglichst 11.2.0.3 sein, frühere Versionen erfordern das Einspielen von Patches.

Das Tool kann auch auf dem Datenbankserver selbst gestartet werden, dann muss aber im Fall von UNIX als Server-Betriebssystem für eine stabile Ausgabe von X11 Sorge getragen werden. Aus diesem Grund wurde ein Windows-PC verwendet. Ideal wäre ein Terminalserver oder ein Client in einer Virtual-Desktop-Umgebung, denn die Abläufe mit dem DMU dauern in der Regel sehr lange und während der Migration wäre ein Netzwerkausfall zwischen Datenbank und DMU-Client verheerend, ebenso wie ein Absturz des Client-Computers selbst.

Der Scan erfordert SYSDBA-Berechtigungen und kann während der Produktionszeiten erfolgen. Die Parallelität, mit der der DMU die Datenbank scannt, kann konfiguriert werden, läuft nur ein Prozess, dauert es entsprechend länger. In der Praxis konnten wir mit 8 Scan-Prozessen ohne Probleme während des Betriebes arbeiten, in den Nachtstunden wurde mit 16 Prozessen gearbeitet. Ein Scan dauerte etwa 3 Stunden.

migstattab

Bei Tests ergab sich die Situation, dass während des Scans die Netzwerkverbindung abbrach. Dauerte dieser Unterbruch zu lange, verlor der DMU die logische Verbindung zur Datenbank und reagierte nicht mehr. Nach einem Neustart erkennt der DMU die Situation und versucht, sein internes Repository (DMU-Tabellen im SYS-Schema) zu bereinigen. Dies kann sehr lange dauern und der DMU ist währenddessen nicht benutzbar. In einigen Fällen kam dieser Vorgang gar nicht mehr zum Ende. Entfernte man die Sessions des DMU aus der Datenbank, startete der Prozess bei der nächsten DMU-Anmeldung von Neuem. Einzige Abhilfe brachte in dieser Situation das Deinstallieren des Repositories. Dies kann mit Hilfe des Skriptes drop_repository.sql geschehen, das sich im /admin-Verzeichnis des Tools findet, und hat keine Nebenwirkungen: Danach kann das Tools sich wieder an der Datenbank anmelden und baut ein neues Repository auf. Danach ist natürlich ein frischer Scan nötig.

Bereinigung

DMU_edit_row

Ist die Bestandsaufnahme abgeschlossen, kann in die Ergebnisanalyse eingestiegen werden. In unserem Fall wurde zunächst versucht, die ermittelten Probleme in möglichst viele gleichartige Klassen zu unterteilen, die dann mit Skripten angegangen werden konnten. Zunächst wurde ein Skript erstellt, dass alle Tabellen mit BYTE-Spaltendefinitionen in CHAR-Definition umwandelt. Dies kann schlicht mittels „alter table .. modify“ erfolgen. Dann wurden individuelle Lösungen für die „over type limit“-Fälle geschneidert, meist wurden hier VARCHAR2-Felder in CLOB imgewandelt werden, dazu legt man am Besten eine temporäre CLOB-Spalte an, kopiert den Inhalt der VARCHAR2-Spalte mit einem UPDATE-Statement, lösche diese und benennt das CLOB in den ursprünglichen Namen der VARCHAR-Spalte um.

Bei den „Invalid Binary Representation“-Fällen war ein wenig detektivischer Spürsinn gefragt. Mit etwas Phantasie gelang es in den meisten Fällen den ursprünglichen Zeichensatz zu erraten. Dann konnten spezialisierte Update-Statements geschrieben werden, die die ungültigen Zeichen zusammengefasst bereinigten. Bei der Entwicklung dieser Korrekturscripte wurde versucht, die Datenqualität gleich dauerhaft zu verbessern, und die eine oder andere Stunde an Recherche über die korrekte Schreibweise osteuropäischer Orte und internationaler Produktbezeichnungen aufgewendet.

Die verbleibenden Fälle, das waren diejenigen, die weniger als zehn Vorkommen aufwiesen, wurden in Einzelfallbearbeitung bereinigt. Der DMU bietet hierzu ein schönes interaktives Interface an, dass die fragwürdigen Zeichen gleich farblich hervorhebt.

Ist die in der Datenbank vorhandene Software in einem eigenen Schema installiert und von dem Schema, in dem die Daten liegen, getrennt, so hat man Glück und kann das Software-Schema exportieren und löschen und anschließend befinden sich keine problematischen Objekte mehr im Data Dictionary. Im vorliegenden Fall war dies nicht möglich, und die betroffenen Trigger und Packages mussten per Skript gelöscht werden. Zum Re-Installieren der Software nach der Migration muss dann natürlich die Software entweder neu installiert werden können. Ist kein Installationsmechanismus vorhanden, müssen diese Objekte, ebenfalls per Skript, neu angelegt werden. Hierfür hat es sich nach einigen Tests mit Perl und dem SQL Developer als am sinnvollsten erwiesen, die Definitionen dieser Objekte vorher mit DBMS_METADATA.GET_DDL zu extrahieren und entsprechende Installationsskripte erstellen zu lassen. Um Umstände zu vermeiden, wurde das PERFSTAT-Schema, das ebenfalls betroffen war, kurzerhand entfernt – PERFSTAT kann hinterher neu angelegt werden.

Zum Abschluss empfiehlt es sich, einen Blick auf den Volumenzuwachs zu werfen. Durch die Multibyte-Repräsentation wächst während der Konvertierung die Datenmenge. Es ist also entsprechend Platz in ASM oder den Filesystemen vorzusehen und darauf zu achten, dass die Datafiles hinreichend Reserven aufweisen oder auf AUTOEXTEND stehen. In unserem Fall haben wir etwa 10% Volumenzuwachs gesehen, das entsprach auch der Vorabschätzung des DMU.

Die Bereinigungsphase ist abgeschlossen, wenn das Status Panel des DMU nach einem abschliessenden Scan den Status „ready for conversion“ anzeigt.

Konvertierung

Vor der Konvertierung sollte sichergestellt werden, dass für die umfangreichen UPDATEs, die das Tool absetzt, genügend Platz für die Archive Logs bereitsteht, bzw ob es sinnvoll ist, ARCHIVELOG während der Migration komplett abzuschalten, was sich natürlich sehr positiv auf die Laufzeit auswirkt.

Es gibt in der Version 1.1 des DMU einen Bug, der während der Konvertierung zu einem Abbruch mit dem Fehler „ORA-22839: Direct updates on SYS_NC columns are disallowed“ führen kann. Um dies zu vermeiden, sollte vor der Konvertierung ein Event 22838 gesetzt werden: „alter system set events ‚22838 TRACENAME CONTEXT LEVEL 1, FOREVER'“.

Vor der Konvertierung sollten zudem alle Jobs abgeschaltet werden („alter system set job_queue_processes=0“).

Die Konvertierung selbst konnte ohne Probleme durchgeführt werden. Die Konvertierungszeit lag bei 17 Stunden. Sollten während der Konvertierung einfache Probleme wie eine volle FRA oder ein fehlendes AUTOEXTEND auftreten, hält DMU an und bietet die Möglichkeit, den Vorgang fortzusetzen, wenn das Problem behoben wurde.

conversion_successfull

Nacharbeiten

Nach der Konvertierung ist der Datenbank-Zeichensatz umgestellt, nun müssen eventuell noch entsprechende Client-Settings angepasst werden, zum Beispiel die Konfiguration von NLS_LANG.

Außerdem ist es empfehlenswert, den Parameter NLS_LENGTH_SEMANTICS=CHAR in der Datenbank zu setzen und die Nls_Length-Semantics-Konfiguration der Clients anzupassen, damit zukünftige Objekte nicht in BYTE-Semantik angelegt werden. Beim SQL Developer kann diese Einstellung in den Settings gesetzt werden. Hier empfiehlt sich eine entsprechende Information aller Entwickler. Auch bei Software-Lieferprozessen, die oft in der Unix-Shell mit sqlplus erfolgen, sollte darauf geachtet werden, hier die richtige Konfiguration, auch von NLS_LANG, zu wählen. Wenn Software-Pakete weiterhin im alten Zeichensatz geliefert werden und eingespielt werden sollen, muss die Variable NLS_LANG beim Aufruf von SQLPlus auf dem Wert für den Zeichensatz stehen, in dem die Datei erzeugt wurde.

sqldeveloper_nls_settings

Nach dem evtl. erforderlichen Re-Import von Software sollten alle Datenbankobjekte unter besonderer Beachtung der korrekten NLS-Settings neu kompiliert werden – ebenso die Views und Materialized Views, die sich evtl vorher auf Tabellen mit BYTE-Semantik bezogen haben. Es empfiehlt sich eine abschließende Kontrolle in dba_tab_columns (CHAR_USED=C) und dba_plsql_object_settings (nls_length_semantics), ob alle Objekte in Char-Semantik vorliegen.

Wird Forms verwendet, muss auch auf dem Forms-Server die NLS-Konfiguration angepasst sowie alle Forms-Module neu übersetzt werden, da sich die Signatur in der Datenbank aller Wahrscheinlichkeit nach geändert hat.

Schnittstellen

Für dateibasierte Schnittstellen, inklusive XML, dass direkt aus der Datenbank erzeugt wird, muss geprüft werden, ob diese zukünftig in Unicode liefern dürfen. Ist dies nicht der Fall, muss die Ausgabe entsprechend konvertiert werden – zum Beispiel mit Hilfe der Funktionen utl_file.put_raw und utl_i18n.string_to_raw.

Sind Clients nicht Unicode-fähig, können sie weiterhin im alten Zeichensatz betrieben werden, wenn deren NLS-Konfiguration entsprechend eingestellt ist (z.B. auf WE8ISO8859P15). Bei diesem Mischbetrieb können sich allerdings Probleme beim Liefern von ISO8859-XML-Dateien ergeben. Bisher im Datenbestand vorhandene Inhalte sind 1:1 abbildbar, da AL32UTF8 eine Obermenge von WE8ISO8859P15 und ISO8859 ist. Nach der Unicode-Umstellung können allerdings auch Unicode-Zeichen eingegeben werden, die in ISO8859 nicht darstellbar sind. Diese Zeichen würden dann im XML durch das Ersetzungszeichen ersetzt werden. Im ungünstigsten Fall könnte also das Ersetzungszeichen „¿“ statt eines kyrillischen Zeichens ausgegeben werden.

Quellen