Beiträge

Oracle 19c DBMS_JOB Konvertierung mit Tücken

Unlängst machte ich bei einer Datenbank-Migration Bekanntschaft mit einer der vielen Verhaltensänderungen, wie sie bei Versionswechsel immer wieder vorkommen.

Der Kunde hatte sich entschieden seine bereits ans Herz gewachsene Oracle 11.2.0.4er Datenbank auf aktuellen Stand zu bringen und sich folgerichtig für die Oracle 19c Version entschieden, welche ja eine „Long Term Support“ Version ist.

Da die Applikationslogik bereits zuvor in einzelne Schemas aufgeteilt war, wählte ich als Migrationsmethode Datapump Export/Import.

DBMS_JOB konvertiert

Nach dem ersten Test-Import und der für Export/Import obligatorischen Analyse der Importfehler stellte ich mit Überraschung fest, dass die vorhandenen Datenbank Jobs, welche zuvor als klassische DBMS_JOB angelegt waren, nun automatisch in neue Scheduler-Jobs „konvertiert“ wurden.

Dieses Verhalten der automatischen Konvertierung kannte ich bisher nur bei einem klassischen Upgrade der Datenbank und es wird auch erst seit Version 19c so gehandhabt.

Das nun auch automatisch neue Scheduler-Jobs bei einem Datapump Import angelegt wurden, überraschte mich erstmal, war aber bei näherer Betrachtung durchaus logisch.

Wie inzwischen allgemein bekannt sein sollte, ist das bereits in die Jahre gekommene DBMS_JOB Package zur Verwaltung von klassischen Datenbank Jobs bereits seit Version 12.2.0.1 „deprecated“, was in der Praxis bedeutet, dass es zwar noch existiert, jedoch in zukünftigen Versionen jederzeit „desupported“ bzw. auch entfernt werden könnte.

Oracle empfiehlt daher komplett auf den „Scheduler“ (DBMS_SCHEDULER) umzusteigen, was in jedem Fall sinnvoll ist, bietet dieser doch wesentlich mehr Funktionalität.

Mit der Version 19c geht Oracle noch einen Schritt weiter und baut eine automatische Konvertierung für klassischen Jobs ein. Das bedeutet, dass das alte DBMS_JOB API noch wie gewohnt verwendet werden kann, Oracle jedoch im Hintergrund automatisch aus jedem neuen DBMS_JOB in Wirklichkeit einen Scheduler Job erzeugt. Das Package DBMS_JOB dient dabei nur mehr als Wrapper um die Rückwärtskompatibilität zu gewährleisten.

Unter der Haube werkt somit nur mehr der Scheduler (das Mapping zwischen „alten“ und „neuen“ Jobs findet man übrigens in der neuen Dictionary Tabelle: SCHEDULER$_DBMSJOB_MAP).

Damit ist auch das Verhalten während meines Datapump Imports erklärt: Da hier die Jobs ebenfalls neu angelegt wurden, erhalte ich auch sofort die dazugehörenden Scheduler Jobs.

SQL> select job,schema_user,what from dba_jobs where job=844;

JOB SCHEMA_USER WHAT
------------- ----------- -------------------------------------
844 DWH dbms_mview.refresh('"DWH"."MVIEW1"');


SQL> select job_name,owner,job_action from dba_scheduler_jobs 
where job_name like 'DBMS_JOB$_844';

JOB_NAME OWNER JOB_ACTION
------------- ---------- -------------------------------------
DBMS_JOB$_844 DWH dbms_mview.refresh('"DWH"."MVIEW1"');

Das Mapping zwischen „alten“ und „neuen“ Jobs findet man übrigens in der neuen Dictionary Tabelle: SCHEDULER$_DBMSJOB_MAP):

SQL> select * from SCHEDULER$_DBMSJOB_MAP where dbms_job_number=844;

DBMS_JOB_NUMBER JOB_OWNER JOB_NAME
--------------- --------- --------------
844 DWH DBMS_JOB$_844

Allgemeine DBMS_JOB Verhaltensänderungen

Trotz Automatismus dürfen folgende Änderungen nicht unerwähnt bleiben:

Berechtigungen

Da es sich nun immer um Scheduler Jobs handelt (auch wenn diese mittels DBMS_JOB angelegt werden) und damit um Datenbankobjekte, muss der User zwingend die Berechtigung zum Anlegen dieser Objekte über das „CREATE JOB“ Privileg erhalten, um weiterhin Jobs über DBMS_JOB anzulegen und zu verwalten.

Transaktionsverhalten

Verwendet man in einer früheren Version als 19c DBMS_JOB zur Verwaltung der Jobs, muss immer explizit ein „commit“ verwendet werden, um die jeweilige Transaktion abzuschließen.

Ab Oracle 19c ist dies nun nicht mehr notwendig – der Scheduler Job wird implizit angelegt.

Trotzdem bleibt die Transaktionsfunktionalität bei der Verwendung von DBMS_JOB erhalten.

Stolperstein NLS-Einstellungen

Nachdem die Jobs während meines Datapump Imports automatisch in Scheduler Jobs konvertiert wurden, war hier für mich als DBA eigentlich nichts weiter zu tun.

Die Freude währte allerdings nur kurz, denn der Kunde machte mich umgehend auf ein seltsames Phänomen aufmerksam: Einige Spalten in seinen Materialized Views hätten plötzlich seltsame Werte bekommen!

Zahlen, die in VARCHAR2 Feldern als Strings gespeichert waren, hatten nun wie von Geisterhand 6 Nullen als Nachkommastelle bekommen.

Meine erste Reaktion war natürlich sofort das Konstrukt „Zahlen in Strings zu speichern“ in Frage zu stellen, allerdings hatte dieser Umstand leider wie so oft eine historische Berechtigung und mit dem eigentlichen Problem gar nichts zu tun.

Lediglich die Auswirkungen eines ganz anderen Problems kamen aber genau an dieser Stelle glücklicherweise an die Oberfläche: Die Jobs, welche den Refresh dieser Materialized Views durchführten, waren genau jene Jobs welche beim Import automatisch konvertiert wurden.

Analyse

Nach einer kurzen Analyse war klar: Bei der Neuanlage der ursprünglichen Jobs während des Imports wurden offensichtlich geänderte NLS-Settings verwendet!

Durch die besondere Konstellation von mehreren verschachtelten Views, MViews und DB-Links führten diese NLS-Settings (konkret die Einstellung des Parameters NLS_NUMERIC_CHARACTERS) dazu, dass einige Zahlen nun in den MViews falsch dargestellt wurden.

Damit war das Problem erkannt und nach einigen Tests schnell behoben.
Das NLS-Environment für einen bestehenden Scheduler-Job lässt sich übrigens auch im Nachhinein einfach ändern (man muss also nicht den kompletten Job neu erstellen):

begin
sys.dbms_scheduler.set_attribute('"USER1"."DBMS_JOB$_1185"','NLS_ENV',
'NLS_LANGUAGE=''GERMAN'' NLS_TERRITORY=''GERMANY'' NLS_CURRENCY=''€'
'NLS_ISO_CURRENCY=''GERMANY'' NLS_NUMERIC_CHARACTERS='',.'
' NLS_DATE_FORMAT=''DD.MM.RR'' NLS_DATE_LANGUAGE=''GERMAN'
' NLS_SORT=''GERMAN''');
end;
/

Fazit:

  • DBMS_JOBs werden ab Oracle 19c automatisch in Scheduler Jobs „konvertiert“ (sowohl beim Upgrade wie auch beim Import) – das alte DBMS_JOB Interface bleibt vorerst vollständig erhalten.
  • Besser vor einem Upgrade alle DBMS_JOBs überprüfen und kontrolliert durch DBMS_SCHEDULER Jobs ersetzen.
  • Besonders beim Import vorab die NLS-Settings von Jobs überprüfen.

Mein persönlicher Tipp an dieser Stelle:

Auch wenn gute Automatismen vorhanden sind, sollte man sich immer schon im Vorfeld eines geplanten Versionswechsels mit bekannten Verhaltensänderungen auseinandersetzen und diese auch bereits vorab gelöst haben.

Dann gibt es auch keine unliebsamen Überraschungen mit unbekannten „Side-Effects“.