Die häufigsten Einsatzfälle eines Function Based Index dürften sein:
An dieser Stelle sollen zwei besondere Einsatzmöglichkeiten solcher Indices vorgestellt werden.
Wir hatten schon öfter in Applikationen folgendes Szenario: In Tabellen soll nicht physikalisch gelöscht werden, sondern nur logisch durch Setzen eines Flags. Gleichzeitig soll ein bestimmtes Merkmal (z.B. ein Name) nur innerhalb der aktiven Einträge eindeutig sein, um anhand dieses - in einer Maske angezeigten - Kriteriums suchen zu können. Ein Beispiel zur Demonstration des Problems:
Ein "normaler" UNIQUE Index hilft hier nicht weiter. Kein Name ist Unique, und auch die Kombination aus Status und Name ist es nicht:
Was tun? Ein Ansatz wäre, vor neuen Einträgen zunächst die Anzahl aktiver Datensätze mit diesem Wert zu zählen, und in dem Fall, dass die Anzahl > 0 ist, den Wert abzulehnen. Sinnvoller wäre es aber, wenn die Datenbank selber solche Anforderungen erzwingen würde. Dann können sie in keinem Fall umgangen werden. Hier kann ein Funktionsbasierter Index weiterhelfen. Der Trick dabei ist, dass NULL-Werte nicht indiziert werden:
Ziel erreicht. Die Eindeutigkeit für aktive Datensätze - und nur für aktive Datensätze - wird durch die Datenbank erzwungen.
Eine andere Fragestellung: Sie haben in Ihrem Workflow eine Tabelle mit zu erledigenden Aufträgen. Es werden laufend neue Einträge mit dem Status 'WAITING' eingetragen. Ein Job arbeitet die Aufträge ab und setzt dabei den Status z.B. zuerst auf 'IN PROGRESS' und am Ende auf 'DONE'. Sie werden sehr bald sehr viele Einträge haben, wobei in der Spalte "Status" nur drei (oder vier: ERROR im Fehlerfall) Werte stehen. Nur ein sehr geringer Prozentsatz davon wird WAITING sein. Aber die sollen effektiv gefunden werden.
Vielleicht denken Sie jetzt: "Wenige unterschiedliche Werte? Aha - Bitmap Index". Nun, das wäre das schlechteste, was Sie tun können, da die Tabelle laufend geändert wird.
Alternative 2 wäre ein normaler B*Tree-Index mit Histogrammen. Das funktionert, solange Sie beim Status nicht mit Bind-Variablen arbeiten und ausgerechnet bei der ersten Ausführung nach einem anderen Status gesucht haben. Allerdings wird der Index unnnötig groß.
Alternative 3: Sie gehen genauso vor wie im ersten Beispiel beschrieben:
Selbstverständlich können Sie hier auch mit DECODE arbeiten, und es ist letztlich unerheblich, welcher Wert GENAU im Index steht. Es könnte genauso gut 'WAITING' selber sein.
Hier ist die Zielsetzung eine andere als oben: Der Zugriff soll beschleunigt werden. Entsprechend muss nun beim SELECT-Befehl darauf geachtet werden, dass der Index auch wirklich verwendet wird. Das heisst, die Funktion muss auch in der WHERE-Klausel stehen:
Anmerkung: Aus Platzgründen wurden Leerzeichen aus dem Plan entfernt
Wenn Sie nicht - oder nicht mehr - wissen, wie ein funktionsbasierter Index angelegt wurde, schauen Sie in DBA_IND_EXPRESSIONS nach.
Funktionsbasierte Indices sind erfreulicherweise seit Version 9.2 auch in der Standard Editon von Oracle enthalten; davor waren sie auf die Enterprise Edition beschränkt.
Quelle:Thomas Kyte, Expert Oracle Database Architecture. 9i and 10g Programming Techniques and Solutions, Apress, 2005