Montag, August 01, 2016

Spaltenvergleichen mit NULL-Werten

Randolf Geist hat vor kurzem einen interessanten Artikel zu einem Thema veröffentlicht, mit dem man sich beim Schreiben komplexerer SQL-Queries regelmäßig herumschlagen muss: dem Vergleichen von Spalten, in denen NULL-Werte auftauchen können. Für die Prüfung der Gleichheit von Werten bedarf die korrekte Behandlung von NULL-Werten bereits eines recht sperrigen Ausdrucks:
column1 = column2 or (column1 is null and column2 is null)
Und noch unhandlicher wird der Ausdruck, wenn man die Ungleichheit von Werten prüfen möchte:
column1 != column2 or (column1 is null and column2 is not null) or (column1 is not null and column2 is null)
Um solche Konstrukte vermeiden zu können, wird bisweilen ein NVL um die Vergleichswerte gesetzt, um den möglichen NULL-Wert durch eine Alternative zu ersetzen, von der man sicher ist, dass sie außerhalb des Wertebereichs der Spalte liegt - aber wann kann man sich in einem solchen Punkt wirklich sicher sein?

Eine andere beliebte Variante dazu ist die Verwendung der lange Zeit nicht dokumentierten Funktion SYS_OP_MAP_NONNULL, die in 12c schließlich in der Doku erscheint, aber immer noch nicht im SQL language manual. Diese Funktion hat allerdings einen Nachteil: sie ergänzt ein Byte zu jedem Input-Wert, was dazu führt, dass sie bei Verwendung von Spalten mit der maximalen Größe für den verwendeten Datentyp einen Fehler hervorruft (nämlich "ORA-01706: user function result value was too large"). Als Alternative dazu wurde gelegentlich die Verwendung von decode vorgeschlagen - etwa von Stew Ashton, dessen zugehörigen Artikel ich hier gelegentlich erwähnt hatte. Da decode NULL-Werte als vergleichbar ansieht, werden die erforderlichen Prüfungen deutlich übersichtlicher - für den Fall der Gleichheit:
decode(column1, column2, 0, 1) = 0
Und für die Ungleichheitsprüfung:
decode(column1, column2, 0, 1) = 1
Hier kommt aber seit Version 11.2.0.2 eine problematische Optimierung ins Spiel: der Fall der Gleichheitsprüfung (aber nicht der der Ungleichheitsprüfung) wird intern auf die Verwendung von SYS_OP_MAP_NONNULL umgeschrieben, was dann wiederum die Probleme mit den Maximallängen hervorruft. Zusätzlich kommt noch hinzu, dass die SYS_OP_MAP_NONNULL-Funktion in Randolfs Test langsamer ist als das nicht umgeschriebene decode und langsamer als die verbose Standard-Variante. Insofern sollte man SYS_OP_MAP_NONNULL und die implizite Umschreibung von decode seit 11.2.0.2 unter Umständen besser vermeiden und fix control 8551880 verwenden, um die implizite Umwandlung zu vermeiden. Zu hoffen ist, dass Oracle gelegentlich eine solidere Lösung für dieses Problem zur Verfügung stellen kann.

Keine Kommentare:

Kommentar veröffentlichen