Umgang mit virtuellen Spalten in Oracle 11g
von Frank Schneede, ORACLE Deutschland GmbH
Die Verwendung von Ausdrücken wird durch die Oracle Datenbank schon seit langem unterstützt. Ein Beispiel hierfür ist die Verwendung von Ausdrücken in Views oder
function-based Indices. Üblicherweise werden Views dafür genutzt, Berechnungen transparent für den Anwender abzubilden. Das geschieht, indem das Ergebnis einer
Berechnung aus Spalten der zugrundeliegenden Tabelle als neue Spalte in einer View bereitgestellt wird. Seit Oracle 8i besteht die Möglichkeit, Ausdrücke zu
indizieren, welches über die Verwendung von function-based Indices geschieht. In Oracle 11g können nun Ausdrücke als virtuelle Spalten direkt
in den Basistabellen gespeichert werden.
Dieser Artikel zeigt auf, wie flexibel der Einsatz von virtuellen Spalten im Vergleich zu den geschilderten Alternativen ist. Hierbei geht es um die Grundlagen der Verwendung
von virtuellen Spalten und die verschiedenen Aspekte, die beim Umgang mit virtuellen Spalten zu beachten sind:
- Anlegen einer virtuellen Spalte
- Indices und Constraints
- Hinzufügen virtueller Spalten
- Virtuelle Spalten und PL/SQL Funktionen
- Virtuelle Spalten im Data-Dictionary
- Virtuelle Spalten, Speicherplatz und der Cost Based Optimizer (CBO)
- Virtuelle Spalten und Partitionierung
- Einschränkungen bei der Nutzung von Virtuellen Spalten
Anlegen einer virtuellen Spalte
Eine Tabelle, die eine virtuelle Spalte enthält, wird über ein einfaches syntakisches Konstrukt angelegt:
Wie man erkennen kann, wird die virtuelle Spalte über einen einfachen Ausdruck auf Basis der anderen Spalten der Tabelle erzeugt. Das Schlüsselwort VIRTUAL ist
hierbei optional, jedoch erleichtert seine Verwendung die Lesbarkeit des Statements. Werte in virtuellen Spalten werden nicht abgespeichert, sondern lediglich zur Laufzeit berechnet.
Dazu wird der Ausdruck - im obigen Beispiel also c_col1 + c_col2 - benutzt. Diese Vorgehensweise spart auf der einen Seite natürlich Platz, auf der anderen Seite sind jedoch
ein paar Dinge zu beachten, die das Einfügen von Daten betreffen.
Wie man sieht, ist das explizite Füllen einer virtuellen Spalte nicht möglich. Aus diesem Grunde versuchen wir nun, lediglich die physisch vorhandenen Spalten anzusprechen.
Auch dieser Versuch schlägt fehl. Es ist also nicht möglich, virtuelle Spalten in INSERT oder UPDATE Statements direkt anzusprechen. Trotzdem gehören auch virtuelle Spalten
natürlich zur Beschreibung der Tabelle. Das bedeutet, dass die Spalten in dem oben gezeigten INSERT Statement explizit referenziert werden müssen.
Da vollständig qualifizierte SQL Statements ohnehin für jeden DBA eine "best practise" darstellen sollte, ist diese Einschränkung de facto irrelevant. Nun ist unsere
Beispieltabelle also mit Daten gefüllt und kann abgefagt werden.
Indices und Constraints
Virtuelle Spalten können für Indices und Constraints verwendet werden. Hierbei wird der Wert der virtuellen Spalte im Index gespeichert. In dem folgenden Beispiel wird
ein Primärschlüssel Constraint auf der virtuellen Spalte c_col3 angelegt.
Beim Versuch des Einfügens eines neuen Datensatzes mit Werten, die einen schon vorhandenen Wert in der virtuellen Spalte ergeben würden, erfolgt eine Verletzung des
Primärschlüssel Constraints.
Wie erwartet, wird eine ORA-00001 Fehlermeldung ausgegeben.
Wie man sieht, stellt das Anlegen eines Primärschlüssels keine besondere Herausforderung dar. Im folgenden Beispiel wird nun eine Detail-Tabelle angelegt,
deren Fremdschlüssel Constraint auf die virtuelle Spalte c_col3 der Testtabelle verweist.
Beim Einfügen gültiger und ungültiger Datensätze verhält sich das System wie erwartet.
Hinzufügen virtueller Spalten
Selbstverständlich können virtuelle Spalten auch zu einer bereits bestehenden Tabelle mit einem ALTER TABLE Befehl hinzugefügt werden. Im folgenden
Beispiel wird eine weitere virtuelle Spalte ergänzt und mit einem zusätzlichen Check-Constraint versehen.
Wie bereits oben ausgeführt, wird im Index der Wert der virtuellen Spalte als Ergebnis des zugrundeliegenden Ausdrucks abgespeichert. Ein Check-Constraint
wertet zum Zeitpunkt der INSERT- oder UPDATE-Operation den Ausdruck auf Basis der enthaltenen Daten aus. Dieses erscheint offensichtlich, denn
ein Check-Constraint besitzt ja keine Datenstruktur, also keinen Index, in dem Werte abgelegt sein könnten.
Auf unserer neuen virtuellen Spalte c_col4 stellt der Check-Constraint sicher, dass das Produkt der Spalten c_col1 und c_col2 größer als 10 ist.
Ein kleiner Test zeigt, dass der Check-Constraint funktioniert.
Virtuelle Spalten und PL/SQL Funktionen
Es ist möglich, virtuelle Spalten über PL/SQL Funktionen zu versorgen, das heißt als Ganzes oder als Teil des gesamten Ausdruckes. Die einzige
Bedingung, die an die verwendete PL/SQL Funktion gestellt wird, ist die, dass die Funktion deterministisch sein muss. Die Funktion kann in einem Package enthalten
sein. Im folgenden Beispiel wird eine deterministische Funktion erstellt, die die Summe zweier Eingabe-Parameter zurückliefert.
Das Schlüsselwort DETERMINISTIC muss hier angegeben werden um sicherzustellen, dass diese Funktion in einer virtuellen Spalte verwendet werden darf.
Eine weitere virtuelle Spalte c_col5 wird zu unserer Testtabelle hinzugefügt. Diese Spalte enthält die Summe der Spalten c_col1 und c_col2, die
hier jedoch mittels der Funktion f_summiere gebildet wird. Anschließend wird die neue virtuelle Spalte abgefragt.
Man sieht, dass die neue Spalte c_col5 den gleichen Wert hat, wie die virtuelle Spalte c_col3. Es ist für das Verständnis des Datenmodells hilfreich,
Ausdrücke über Programmkonstrukte (Funktionen, Packages) zu definieren, jedoch ist dieses Vorgehen mit Auswirkungen auf die Performance verbunden.
Dieses zeigt sich an einem kleinen Beispiel, in dem 1.000.000 Zeilen mit den Spalten c_col3 und c_col5 abgefragt werden. Zuerst müssen diese Testdaten jedoch
erzeugt werden.
Jetzt befinden sich also 1 Million Testdatensätze in unserer Tabelle. Diese werden über die Spalten c_col3 und c_col5 in zwei unterschiedlichen
Select-Statements abgefragt. Um die Auswirkungen auf die Performance sehen zu können, wird Autotrace aktiviert und Timing gesetzt.
In unserem Vergleich benötigt die Abfrage der virtuellen Spalte c_col5, die auf einer PL/SQL Funktion basiert, ungefähr doppelt so lange wie die
Abfrage auf Basis des Ausdruckes (c_col3). Der I/O-Aufwand für beide Abfragen ist annähernd gleich. Bei einfachen Ausdrücken wie in unserem
Beispiel macht es also durchaus Sinn, die Berechnungslogik in die virtuellen Spalten zu integrieren und den Nachteil in der Performance zu vermeiden.
Virtuelle Spalten auf Basis von PL/SQL Funktionen mit einer geringen Kardinalität können von dem in Oracle 11g eingeführten Feature des Result
Caches profitieren. Ein Performancenachteil gegenüber den "inline" definierten Ausdrücken wird sich dennoch zeigen.
Virtuelle Spalten im Data-Dictionary
Beim Design von Datenodellen ist es wichtig, diese so zu gestalten, dass mit der Abfrage des Data-Dictionary das System möglichst selbsterklärend beschrieben
werden kann. Hierzu sind Kommentare sehr hilfreich, die für physisch vorhandene und virtuelle Spalten angelegt werden sollten, wie im folgenden Beispiel gezeigt.
Informationen über virtuelle Spalten können an unterschiedlichen Stellen im Data-Dictionary gefunden werden. In den folgenden
Abfragen werden einige USER-Dictionary Views gezeigt, die korrespondierenden ALL- und DBA-Views beinhalten die gleichen Informationen.
Das erste Beispiel zeigt die Spalten der Testtabelle mit dem Wert DATA_DEFAULT.
Die Spalte DATA_DEFAULT zeigt hier also die Definition der Ausdrücke, die die virtuellen Spalten beschreiben. Anhand der Data-Dictionary View
USER_TAB_COLUMNS kann man zwischen physisch vorhandenen und virtuellen Spalten unterscheiden.
Der oben angelegte Index kann durch Abfrage der View USER_INDEXES abgefragt werden.
Der INDEX_TYPE zeigt, dass es sich - wie oben gesagt - um einen function-based Index auf der virtuellen Spalte handelt. Weder die virtuellen
Spalten, noch die Ausdrücke des function-based Index werden physisch an einem anderen Ort abgelegt als im Index selbst. Die Data-Dictionary
View USER_IND_EXPRESSIONS zeigt Informationen über den Primärschlüsselindex auf der virtuellen Spalte c_col3.
Diese Informationen im Data-Dictionary sind für jeden DBA wichtig. Es sei an dieser Stelle bemerkt, dass andere Data-Dictionary Views (z. B.
USER_CONS_COLUMNS, USER_CONSTRAINT, USER_COL_COMMENTS, ...) nicht zwischen physisch vorhandenen und virtuellen Spalten unterscheiden.
Virtuelle Spalten, Speicherplatz und der Cost Based Optimizer (CBO)
Wie bereits oben ausgeführt, belegen virtuelle Spalten selbst keinen Speicherplatz. Funktionen wie DUMP oder VSIZE liefern hingegen trotzdem
die "normalen" Werte zurück, denn die Funktionen arbeiten auf dem Ergebnis des Ausdrucks, der der virtuellen Spalte zugrunde liegt. Dieses
Verhalten sieht man im folgenden Beispiel.
Die Tatsache, dass auch mehrere virtuelle Spalten keinen zusätzlichen Platz verbrauchen, läßt sich an dem folgenden Beispiel leicht beweisen.
Es werden zwei Tabellen angelegt und mit jeweils 10.000 Datensätzen gefüllt.
Jetzt lassen sich beide Tabellen über eine einfache Data-Dictionary Abfrage vergleichen.
Wie erwartet, ist der Bedarf an Speicherplatz für beide Tabellen identisch.
Der Cost Based Optimizer (CBO) behandelt physisch vorhandene und virtuelle Spalten gleich, d. h. es wird auf Basis identischer Annahmen kalkuliert, wenn
entsprechende Statistiken fehlen. Durch Aktivierung des AUTOTRACE Feature kann man die Ausführungspläne der Abfragen auf der soeben angelegten Tabelle
t_storage_test_vc sehen. Um den Ausführungsplan lesbarer zu gestalten, wird als erstes ein Update durchgeführt. Anschließend erfolgt die erste
Beispielabfrage.
Da keine Statistiken vorhanden sind, wird dynamic sampling verwendet. Der CBO nimmt an, dass nahezu alle Sätze der Tabelle
die Abfragekriterien erfüllen. Die zu c_col1 korrespondierende Spalte ist c_col4 und wird über den Ausdruck UPPER(c_col1) erzeugt.
Die Abfrage ergibt folgendes Bild.
Der CBO ermittelt eine andere Kardinalität für die virtuelle Spalte, ungeachtet der Tatsache, dass c_col4 sich direkt aus c_col1 ergibt.
Offenbar legt der CBO die Standard-Selektivität von 1% für einen Ausdruck der Form "function(column)=literal" an, um zu diesem Ergebnis zu kommen.
Interessant ist, dass auch hier dynamic sampling zugrunde gelegt wird. Das bedeutet, dass auch auf virtuellen Spalten Statistiken berechnet werden können.
Dieses wiederum hat zur Folge, dass der CBO mit Statistiken auf Spaltenebene und natürlich mit Histogrammen eine wesentlich genauere Abschätzung der Kosten des
Statements vornehmen kann. Also werden nun Statistiken berechnet und die Abfrage auf die virtuelle Spalte c_col4 wird erneut ausgeführt.
Man sieht auf den ersten Blick, dass nun die korrekte Kardinalität zugrunde gelegt wird. Dieses läßt sich anhand weiterer
Abfragen auf Tabellen- und Spaltenebene verifizieren.
Die Statistiken scheinen wesentlich besser zu sein. Die Spalte DENSITY besitzt für die Spalten c_col1 und c_col4 andere Werte, da Histogramme
angelegt worden sind. Die Histogramme wurden automatisch erzeugt, da diese Spalten in den Abfragen vor Berechnung der Statistiken verwendet worden
sind. Die Verwendung aller in Prädikaten verwendeten Spalten wird in den neueren Versionen von Oracle durchgeführt, um das Berechnen
der Statistiken noch präziser automatisiert ausführen zu können.
Virtuelle Spalten und Partitionierung
Oben wurde ausgeführt, dass virtuelle Spalten in Primärschlüsseln verwendet werden können. Ebenso können sie seit Oracle 11g
als Partitionsschlüssel in partitionierten Tabellen verwendet werden. Dieses funktioniert auch für sub-partitionierte Tabellen, in denen die virtuelle
Spalte sowohl in der Partition als auch in der Subpartition als Schlüssel verwendet wird. Die Funktionsweise soll an einem einfachen Beispiel gezeigt werden,
das auf den Daten der Data-Dictionary View ALL_OBJECTS beruht. Die Spalte c_col_p1 ist hier eine virtuelle Spalte, deren Wert auf Basis der Spalten c_col_c1
und c_col_c2 berechnet wird.
Nachdem die partitinierte Tabelle mit 8 Partitionen erstellt worden ist, wird diese nun mit Daten versorgt. Eine kleine Abfrage zeigt
die Datenverteilung. Zum Abschluß der Vorbereitungen werden die Statistiken auf der partitionierten Tabelle berechnet.
Die folgenden Abfragen sollen nun zeigen, wie auch bei der Partitionierung mit virtuellen Spalten eine Partition Elimination funktioniert.
Über das AUTOTRACE Feature wird der Ausführungsplan erzeugt.
Man sieht, dass durch den Equi-Join auf dem Partitionsschlüssel wie erwartet alle Partitionen elimiert werden, außer der Partition, die die
gewünschten Daten enthält. Das folgende Beispiel zeigt einen LIKE-Ausdruck auf dem Partitionierungsschlüssel:
Man sieht, dass in diesem Beispiel ein PARTITION LIST ITERATOR für den LIKE-Ausdruck gewählt wird. Die zu lesende Partition wird also erst zur
Laufzeit ermittelt. Dieses funktiniert natürlich nur für LIKE-Ausdrücke, die KEINE führenden Wildcards besitzen.
Einschränkungen bei der Nutzung von Virtuellen Spalten
Wie man aus den obigen Ausführungen und Beispielen entnehmen konnte, sind virtuelle Spalten ein sehr mächtiges Werkzeug. Es gibt jedoch
noch einge Einschränkungen, die bei der Benutzung virtueller Spalten beachtet werden müssen:
- Virtuelle Spalten können nur in sogenannten Heap-organisierten Tabellen verwendet werden. Virtuelle Spalten in index-organized, externen, Objekt-, Cluster-
oder temporären Tabellen sind nicht unterstützt.
- Der Ausdruck in der AS-Klausel der Defintion der virtuellen Spalte hat folgende Einschränkungen:
- Der Ausdruck darf sich nicht auf eine andere virtuelle Spalte beziehen.
- Jede Spalte, auf die sich die virtuelle Spalte bezieht, muss sich in der gleichen Tabelle befinden.
- Eine deterministische benutzerdefinierte Funktion kann verwendet werden. In diesem Fall kann die virtuelle Spalte jedoch NICHT als Partitionierungsschlüssel genutzt werden.
- Das Ergebnis des Ausdruckes muss ein skalarer Wert sein.
- Eine virtuelle Spalte darf kein Oracle-supplied Datentyp (z. B. LCR-Typ) sein, ebenso kein benutzer-definierter Typ, LOB oder LONG RAW.
Mehr zu diesem Thema bzw. zu weiteren Themen rund um die Datenbank lesen Sie in den nächsten Ausgaben ...
Zurück zur Community-Seite
|