- Fachgebiet Datenbanken und Informationssysteme

Werbung
Semantik und Realisierung einer
erweiterten Relationenalgebra für
temporale Datenbanken
Diplomarbeit
im Studiengang Mathematik mit Studienrichtung Informatik
vorgelegt von
Christian Stahlhut
Matrikelnummer: 1937473
Universität Hannover
Institut für Informationssysteme
Fachgebiet Datenbanksysteme
Prüfer: Prof. U. Lipeck
Zweitprüfer: Prof. R. Parchmann
Hannover, den 27. Juli 2004
Zusammenfassung
In dieser Arbeit wird ein Konzept zur relationalen Modellierung von zeitabhängigen
( temporalen“) Daten beschrieben. Zunächst wird der zugrundeliegende Zeitbegriff nä”
her erläutert. Dann kann die klassische Relationenalgebra um einen Zeitbezug erweitert
werden. Anhand dieser Erweiterung wird diskutiert wie temporale Datenbanken zu modellieren sind und welche zusätzlichen Integritätsbedingungen es zu beachten gilt.
Durch Anfragebeispiele für konkrete temporale Datenbanken wird versucht eine gewisse Pragmatik bezüglich der erweiterten Relationenalgebra aufzubauen.
Ein weiterer Schritt zur Realisierung der erweiterten Relationenalgebra ist die Optimierung der erweiterten Operatoren.
Abschließend wird eine beispielhafte Implementierung der Algebra als Anfragesprache
auf Grundlage des relationalen Datenbankmanagementsystems Oracle vorgestellt.
Inhaltsverzeichnis
1. Einleitung
5
2. Semantik temporaler Daten
2.1. Zeitstempel, Chronons und Granularität . . . . . . . . . . . . . . . . . .
2.2. Modellierung des Zeitstempels . . . . . . . . . . . . . . . . . . . . . . . .
2.3. Gültigkeitszeit, Transaktionszeit und benutzerdefinierte Zeit . . . . . . .
7
7
7
8
3. Definition der erweiterten Relationenalgebra
3.1. Relationen . . . . . . . . . . . . . . . . . .
3.2. Intervalle . . . . . . . . . . . . . . . . . .
3.3. pack und unpack . . . . . . . . . . . . . .
3.4. Erweiterung der Relationenalgebra . . . .
.
.
.
.
10
10
15
18
22
4. Modellierung temporaler Datenbanken
4.1. Integritätsbedingungen . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2. Tupel- oder Attributzeitstempel . . . . . . . . . . . . . . . . . . . . . . .
4.3. Zukunft, Gegenwart und Vergangenheit . . . . . . . . . . . . . . . . . . .
24
24
29
32
5. Pragmatik – Anfragebeispiele
5.1. Beispiele aus [Bei2001a]– ein Vergleich mit TSQL2 . . . . . . . . . . . . .
5.2. Beispiele aus [DDL2003a] . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.3. Beispiele zu Gruppierung und Aggregation . . . . . . . . . . . . . . . . .
35
35
38
40
6. Optimierung
6.1. Zerlegung in Teilintervalle – split
6.2. Vermeidung von unpack und pack .
6.3. Verbesserungen für pack . . . . . .
6.4. Verbesserungen für unpack . . . . .
6.5. Verbesserungen für split . . . . .
.
.
.
.
.
44
44
46
54
57
57
7. Realisierung
7.1. Erweiterung des DBMS . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.2. Übersetzung von Termen . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.3. Implementierung des Evaluators . . . . . . . . . . . . . . . . . . . . . . .
61
61
69
72
3
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Inhaltsverzeichnis
8. Ausblick
75
A. Intervalle und Intervalloperatoren
77
B. Grammatik der Anfragesprache
B.1. Terminalsymbole . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
B.2. Grammatik . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
78
78
78
4
1. Einleitung
Motivation und Zielsetzung
Veränderungen unter dem Einfluß der Zeit sind ein alltägliches Phänomen. Zeitliche
Veränderung zu beschreiben erfordert gewisse Begriffe. Sollen solche Beschreibungen in
einem Datenbankmanagementsystem (DBMS) realisiert werden, sind also zunächst entsprechende Begriffe zu schaffen. Moderne kommerzielle DBMS unterstützen jedoch den
Umgang mit zeitabhängigen (temporalen) Daten bisher kaum. Allerdings ist heute die
Speicherung großer (historischer) Datenmengen ökonomisch vertretbar, da Speicherkosten fast kein Problem mehr darstellen. Außerdem sind Modellierung und Verarbeitung
temporaler Daten Aufgaben, die immer mehr an Bedeutung gewinnen – zum Beispiel in
Data Warehouses. DBMSe um zeitliche Funktionalität zu erweitern ist also naheliegend.
Ziel dieser Arbeit soll es demnach sein, durch eine erweiterte Relationenalgebra zunächst die Begriffe zu schaffen, die in einem relationalen DBMS (RDBMS) für den Umgang mit temporalen Daten benötigt werden. Ausgehend von dieser Algebra ist exemplarisch eine temporale Erweiterung für das RDBMS Oracle zu realisieren.
Quellen und verwandte Arbeiten
Arbeiten zu diesem Thema entstanden schon vor einiger Zeit (etwa [TCG93a]): Eine
Erweiterung der deskriptiven Anfragesprache SQL (Structured Query Language) um
temporale Elemente wurde unter dem Namen TSQL2 ([Sno95a]) dem ISO-Komitee zur
Standardisierung vorgelegt. Verschiedene Probleme mit dem TSQL2-Ansatz führten jedoch dazu, dass bis heute (2004) keine solche SQL-Erweiterung verabschiedet1 ist.
Einige der Kritiker von TSQL2 veröffentlichten vor kurzem das Buch Temporal Da”
ta and the Relational Model“ ([DDL2003a]), in dem ein alternativer Umgang mit der
Problematik vorgeschlagen wird. Die hier vorgestellte erweiterte Relationenalgebra ist
an den in dieser Quelle beschriebenen Konzepten orientiert.
Zusätzlich werden bereits am Institut entstandenen Arbeiten (sowie deren Quellen) beachtet: In [Rei99a] und [Bei2001a] wird versucht, eine temporale Erweiterung für SQL92
im Sinne von TSQL2 zu schaffen. Eine graphische Anfragesprache für temporale Datenbanken wird in [Kuh97a] beschrieben.
1
Leicht am fehlenden Part 7“ ( SQL/Temporal“) in der SQL-Spezifikation zu erkennen – etwa durch
”
”
eine Suche bei http://iso.org nach ’SQL’.
5
1. Einleitung
Gliederung dieser Arbeit
Der Literatur folgend werden Daten mit einem zeitlichen Bezug versehen, indem ihnen
ein Gültigkeitszeitraum zugeordnet wird. Die Modellierung dieser Zeitstempel geschieht
mit diskreten Intervallen, welche als Zeitspannen zu verstehen sind. In Kapitel 2 wird so
die grundlegende Semantik einer temporalen Datenbank festgelegt.
Danach sind zunächst die Grundlagen für den Umgang mit solchen Intervallen im
relationalen Datenmodell zu schaffen. Davon ausgehend wird die klassische Relationenalgebra um Intervallfunktionalität erweitert (Kapitel 3).
In Kapitel 4 wird dargelegt, wie Integritätsanforderungen einer temporalen Datenbank
durch die erweiterte Relationenalgebra zu formulieren sind. Außerdem ist zu klären wie
die Relationen einer temporalen Datenbank modelliert werden können.
Um die Ausdrucksfähigkeit der Algebra zu testen und die beschriebenen Begriffe zu
konkretisieren, werden in Kapitel 5 Anfragebeispiele diskutiert. In Kapitel 6 wird versucht die erweiterten Operatoren in Hinblick auf Speicherbedarf und Geschwindigkeit zu
verbessern und so eine Implementierung zu ermöglichen.
Eine Beispielimplementierung soll zeigen, ob und wie die erweiterten Relationenalgebra als Anfragesprache auf Basis eines bestehenden RDBMS realisiert werden kann
(Kapitel 7). Schließlich wird in Kapitel 8 ein Ausblick auf weitere Möglichkeiten gegeben, die durch das hier beschriebene Konzept erschlossen werden.
6
Eins-zwei-drei! Im Sauseschritt läuft die Zeit, wir laufen mit.
(Wilhelm Busch)
2. Semantik temporaler Daten
Die Bedeutung von Daten in einem zeitlichen Kontext hängt vom verwendeten Zeitbegriff ab. Deshalb werden im folgenden zunächst die Begriffe Zeitpunkt“ und Zeitraum“
”
”
erläutert, damit eine Semantik für zeitveränderliche Daten angegeben werden kann. Abschließend wird Bezug auf in der Literatur häufig verwendete Zeitbegriffe genommen.
2.1. Zeitstempel, Chronons und Granularität
In einer Datenbank wird jedem Tupel einer Relation stets eine gewisse Aussage zugeordnet. Diese Aussage soll für eine temporalen Datenbank in einen zeitlichen Zusammenhang
gestellt werden, indem ihr ein gewisser Gültigkeitszeitraum zugesprochen – sozusagen ein
Zeitstempel aufgeprägt“ – wird. Die allgemeine Struktur dieses Zeitstempels muss also
”
eine (potentiell unendliche) Menge1 von Zeitpunkten sein. Einem Zeitpunkt (Chronon),
als kleinster in der Datenbank darstellbaren Zeiteinheit, kann wiederum ein (kontinuierliches) Zeitintervall oder eine (endliche) Menge von (atomaren) Zeiteinheiten entsprechen.
Die Länge eines Zeitpunkts2 wird als Granularität bezeichnet.
Bemerkungen:
• Ein Zeitstempel besteht nicht notwendigerweise aus einem Intervall von Zeitpunkten (z.B. bei periodisch wiederkehrenden Ereignissen).
• Es können verschiedene (gleichberechtigte) Arten von Zeitpunkten mit unterschiedlichen Granularitäten existieren (etwa verschieden lange Vorlesungszeiten im Winterund Sommersemester).
• Ein Zeitstempel kann Vergangenheit oder Zukunft (auch beides) enthalten. Dafür
muss jedoch ein Zeitpunkt als gegenwärtig“ festgelegt sein.
”
2.2. Modellierung des Zeitstempels
2.2.1. Natürliche Zahlen als Zeitpunkte
Da die Granularität frei bestimmbar (interpretierbar) ist, sollte es ausreichen ein diskretes3 Zeitmodell zu verfolgen. Damit genügt als Grundmenge von Zeitpunkten die Menge
1
2
diskret oder kontinuierlich – je nach Philosophie
also die Länge des Zeitintervalls eines Chronons im kontinuierlichen Fall oder die Anzahl von atomaren
Zeiteinheiten eines Chronons im diskreten Fall
7
2. Semantik temporaler Daten
der natürlichen Zahlen.
Beispiel: Ist (genau) eine Stunde als Granularität gewählt, dann entspricht der Zeitpunkt
’4’ der vierten Stunde – also der Zeit von 4:00 Uhr bis kurz vor“ 5 Uhr.
”
2.2.2. Intervalle als Zeitstempel
Da in der Praxis häufig Tupel betrachtet werden, deren Attributwerte in einer gewissen
Zeitspanne konstant bleiben, erscheint es sinnvoll ein (geschlossenes) Intervall als Datenstruktur für Zeitstempel zu nutzen: Ist die Aussage eines Tupels zu einem bestimmten
Zeitpunkt gleich der Aussage eines anderen Tupels zum Zeitpunkt danach (oder davor),
so können diese Tupel mit dem entsprechenden intervallwertigen Zeitstempel zusammengefasst werden. Prozesse, die Aussagen an nicht aufeinanderfolgenden Zeitpunkten
identifizieren (etwa periodische Prozesse) werden allerdings mit dieser Wahl nicht so
effizient modelliert.
Beispiel: Mit [4, 9] wäre also der Zeitraum von 4:00 Uhr bis kurz vor“ 10 Uhr gemeint,
”
wenn ein Zeitpunkt einer Stunde entspricht. [4, 4] kann dann mit dem Zeitpunkt ’4’
identifiziert werden.
Bemerkung: Mit den zwei Zeitpunkten b und e mit b ≤ e entspricht das geschlossene
Intervall [b, e] dem rechts offenen Intervall [b, e + 1) und umgekehrt. Aus programmiertechnischen Gründen wird hier die geschlossene Darstellung bevorzugt – auch wenn beide
Darstellung austauschbar sind. Außerdem besteht mit rechts offenen Intervallen eher die
Gefahr undefinierte Intervalle zu erzeugen – etwa durch [b, b).
2.2.3. Temporale Elemente
Mit der im TSQL-Ansatz als Zeitstempel verwendeten Menge von Zeitintervallen ( tem”
porales Element“) ist keine größere Ausdrucksfähigkeit zu erwarten. Ein solches temporales Element kann stets durch mehrere Tupel mit (verschiedenen) Intervall-Zeitstempeln
ohne Verlust nachgebildet werden (vgl. die Beispiele in 5.1). Daher wird hier auf dieses
komplizierende Konzept verzichtet.
2.3. Gültigkeitszeit, Transaktionszeit und
benutzerdefinierte Zeit
In der Literatur zu temporalen Datenbanken sind häufig die Begriffe Gültigkeitszeit
(valid time), Transaktionszeit (transaction time) und benutzerdefinierte Zeit (userdefined time) zu lesen.
Gültigkeitszeit“ bezieht sich auf Aussagen mit Gültigkeitszeitraum.
”
3
Eine Menge ist diskret, wenn sie umkehrbar-eindeutig auf die natürlichen Zahlen abbildbar ist.
8
2. Semantik temporaler Daten
Mit Transaktionszeit“ ist die Protokollierung von Datenbanktransaktionen auf Tu”
pelebene gemeint – Tupel X stand im Zeitraum Z in Relation R“. Zeitstempel für
”
Transaktionszeit sind vom Datenbanknutzer unabhängig und werden allein vom DBMS
verwaltet. Im Sinne eines Logs, also der Protokollierung von Transaktionen, sind Aussagen über die Vergangenheit hier nicht veränderbar4 .
Transaktionszeit läßt sich natürlich über (eine zusätzliche) Gültigkeitszeit nachbilden.
Ein DBMS, das Gültigkeitszeit und Transaktionszeit enthält wird bitemporal genannt.
Als benutzerdefinierte Zeit“ werden Zeitangaben ohne Zeitstempelbezug bezeichnet.
”
Der oben erläuterte Zeitstempel entspricht also eher der Gültigkeitszeit. Im hier vorgestellten Konzept müssen die genannten Zeitbegriffe jedoch nicht weiter unterschieden
werden.
4
Ansätze für einen Umgang mit Transaktionszeit im Hinblick auf Datenrettung sind unter dem Stichwort Flashback Query“ in der Version 10g des Oracle-DBMS zu finden (siehe [OraAD] Kapitel
”
15)
9
3. Definition der erweiterten
Relationenalgebra
Um eine erweiterte Relationenalgebra definieren zu können, wird in 3.1 zunächst erläutert, wie die zugrundeliegende Relationenalgebra definiert ist.
Nach 2.2.2 wird ein Zeitstempel als Intervall modelliert. In 3.2 wird daher ein entsprechender Intervallbegriff eingeführt. Zusätzlich werden Operatoren für den Umgang mit
Intervallen definiert. Bezüglich temporaler Daten werden also die für den Umgang mit
Zeiträumen benutzbaren Begriffe bereitgestellt.
Die dann in 3.3 neu eingeführten Operatoren dienen dazu, eine atomare“, zeitpunkt”
”
artige“ Sicht auf die Information in einer Relation zu erhalten (unpack), bzw. diese
Information möglichst zusammengefasst“ und redundanzfrei“ betrachten zu können
”
”
(pack). Damit läßt sich die zugrundeliegende Relationenalgebra um Funktionalität für
Zeitstempel (bzw. Intervalle) erweitern (3.4).
3.1. Relationen
Die hier aufgeführten Definitionen sollen weitgehend der gewohnten“ klassischen Re”
lationenalgebra entsprechen. Der einzige wichtige Unterschied besteht in der Definition
von Gruppierung und Aggregation: Das Ergebnis einer Aggregationsfunktion ist nicht
auf einen einzigen Wert beschränkt, sondern kann eine Menge von Werten zurückliefern.
Dies wird das grundlegende Konzept für die Formulierung der erweiterten Relationenalgebra in 3.3.
3.1.1. Definition
Eine Relation ist ein 2-Tupel R = (S, I):
• S heißt Schema von R und ist eine Funktion der Form
S : {a1 , . . . , an } −→ D
mit n ∈ N0
wobei der Definitionsbereich def(S) = {a1 , . . . , an } eine Menge von (paarweise verschiedenen) Zeichenketten (den Attributnamen) und D eine Menge von Mengen
(den Wertebereichen oder Datentypen) ist. S ordnet also jedem Attributnamen einen Wertebereich zu.
10
3.1. Relationen
• Sei
T (S) := {t : def(S) −→
[
S(a) mit t(a) ∈ S(a) für alle a ∈ def(S)}
a∈def(S)
eine Menge von Abbildungen, die allen Attributnamen eines Schemas einen Wert
aus dem zugehörigen Wertebereich zuordnet. Eine endliche Teilmenge I von T (S)
heißt Inhalt von R.
Bemerkungen:
• Das Bild im(S) von S ist die Menge aller den Attributnamen zugeordneten Wertebereichen; im(S) ⊆ D.
• Ein 2-Tupel (a, S(a)) ∈ def(S) × im(S) heißt Attribut (von R).
• Ein t ∈ T (S) heißt Tupel und ein t ∈ I ⊂ T (S) entsprechend Tupel von R.
• T (S) ist die Menge aller möglichen Tupel zu einem Schema S.
• Häufig wird R statt I geschrieben1 , z.B. t ∈ R statt t ∈ I. Oder: Ist P eine Relation
mit gleichem Schema wie R, dann ist mit P ⊂ R gemeint, dass der Inhalt von P
Teilmenge des Inhalts von R ist.
• Der Inhalt von R enthält das gleiche Tupel nicht mehr als einmal (keine Duplikate).
Es ist keine bestimmte Reihenfolge der Attribute oder der Tupel festgelegt.
• Ist eine Reihenfolge a1 , . . . , an der Attribute vorgegeben, so wird ein t ∈ T (S) auch
kurz als (t(a1 ), . . . , t(an )) geschrieben.
• Eine Relation wird häufig in Form einer Tabelle dargestellt, z.B:
Name
Alter
Müller
33
Schmidt
35
Schulze
32
Die Namen der Attribute ergeben sich aus dem Tabellenkopf. Die Wertebereiche
werden meist nicht explizit angegeben. Dieser Tabelle entspricht ein Schema mit
den Attributen (Name, string) und (Alter, integer). Der Inhalt der Relation ist
die Menge der Tupel (Müller, 33), (Schmidt, 35) und (Schulze, 32).
3.1.2. Operatoren auf Relationen – Relationenalgebra
Die folgenden Operatoren bilden eine Algebra auf der Menge der Relationen.
Seien X = (S X , I X ) und Y = (S Y , I Y ) zwei Relationen.
1
Ob eine Relation oder deren Inhalt gemeint ist, sollte aus dem Kontext erkennbar sein.
11
3.1. Relationen
Projektion
Sei A eine Teilmenge der Attributnamen von X: A ⊆ def(S X ). Dann wird X durch die
Projektion folgendermaßen auf A eingeschränkt:
πA (X) := (S 0 , I 0 ) mit
S 0 = S X |A = S 0 : A −→ im(S X ) mit S 0 (a) = S X (a) für alle a ∈ A
I 0 = {t|A : t ∈ X}
Erweiterung
Sei M eine Menge, β eine Abbildung der Form β : I X → M und b 6∈ def(S X ) eine
Zeichenkette. Dann ist die Erweiterung von X um b = β definiert als:
εb=β (X) := (S 0 , I 0 ) mit
S 0 : def(S X ) ∪ {b} −→ im(S X ) ∪ {M } mit S 0 |def(S X ) = S X und S 0 (b) = M
I 0 = {t0 ∈ T (S 0 ) : ∃t ∈ X mit t0 |def(S X ) = t und t0 (b) = β(t)}
Umbenennung
Sei a ∈ def(S X ) ein Attributname von X und b 6∈ def(S X ) eine Zeichenkette. Außerdem
sei β : I X → S(a) mit β(t) = t(a). Dann kann das Attribut a von X wie folgt in b
umbenannt werden:
ρb=a := πdef(S X )−{a} (εb=β (X))
Für mehrere Umbenennungen der Form ρb1 =a1 (ρb2 =a2 (. . . (X))) sei auch die Schreibweise
ρb1 =a1 ,b2 =a2 ,... (X) erlaubt.
Selektion
Es sei ϕ eine Selektionsfunktion: ϕ : I X → {wahr, falsch}. Mit σϕ (X) werden alle Tupel
aus X ausgewählt, die der Selektionsfunktion genügen:
σϕ (X) : = (S X , I 0 ) mit
I 0 = {t ∈ X : ϕ(t) = wahr}
Verbund (Join)
Durch den Verbund von X und Y werden alle Tupel verknüpft, die gleiche Werte für
gleichnamige Attribute haben:
Xo
n Y := (S 0 , I 0 ) mit
S 0 : def(S X ) ∪ def(S Y ) −→ im(S X ) ∪ im(S X ) mit S 0 |def(S X ) = S X und S 0 |def(S Y ) = S Y
I 0 = {t ∈ T (S 0 ) : ∃x ∈ X ∧ ∃y ∈ Y mit t|def(S X ) = x ∧ t|def(S Y ) = y}
12
3.1. Relationen
Bemerkung: Haben X und Y keine gleichnamigen Attribute, so entspricht der Verbund dem Kartesischen Produkt von X und Y . Umgekehrt entspricht der Verbund dem
Durchschnitt von X und Y falls X und Y nur gleichnamige Attribute haben.
Vereinigung
Falls X und Y das gleiche Schema (S X = S Y ) haben, ist die Vereinigung wie folgt
definiert:
X ∪ Y : = (S 0 , I 0 ) mit
S0 = SX = SY
I 0 = {t : t ∈ X ∨ t ∈ Y }
Differenz
Haben X und Y das gleiche Schema (S X = S Y ), so ist die Differenz von X und Y
definiert als:
X − Y : = (S 0 , I 0 ) mit
S0 = SX = SY
I 0 = {t : t ∈ X ∧ t 6∈ Y }
Durchschnitt
Mit (S X = S Y ) gilt:
X ∩ Y := X − (X − Y ) = X o
nY
Gruppierung und Aggregation
Sei A eine Teilmenge der Attributnamen von X: A ⊆ def(S X ).
Für alle 1 ≤ i ≤ n ∈ N seien außerdem bi 6∈ def(S X ) paarweise verschiedene Zeichenketten, Mi Mengen und αi (Aggregations-)Funktionen der Form
αi : P(I X ) −→ P(Mi )
Dann gilt:
ΓA # b1 =α1 ,...,bn =αn (X) := (S 0 , I 0 ) mit
S 0 : {b1 , . . . , bn } −→ {Mi , . . . , Mn } mit S 0 (bi ) = Mi
∀i ∈ {1, . . . , n}
I 0 = {t0 ∈ T (S 0 ) : ∃t ∈ πA (X) ∧ ∀i ∈ {1, . . . , n} : t0 (bi ) ∈ αi ({x ∈ X : x|A = t}) }
13
3.1. Relationen
Bemerkungen:
• Ist A = ∅ die leere Menge, dann wird nicht gruppiert und das Ergebnis einer
Aggregationsfunktion wird für ganz X bestimmt.
• Diese Definition der Gruppierung unterscheidet sich in (nur) einem Punkt von
der Herkömmlichen: Eine Aggregationsfunktion liefert anstelle von Werten (aus
einer Menge M ) eine Menge von Werten (aus P(M )) zurück. Der Nutzen dieser
Erweiterung ergibt sich im Umgang mit intervallwertigen Attributen (siehe 3.3.1).
Vereinfachungen: Mit einer Menge G ⊆ I X und einem Attributnamen a ∈ def(S X )
seien folgende abkürzende Schreibweisen möglich:
• count für α(G) := {|G|}
• min(a) für α(G) := {mint∈G t(a)}
P
• sum(a) für α(G) := { t∈G t(a)}
• weitere Aggregationsfunktionen (max, avg, . . . ) analog zu min und sum
Beispiel: Sei folgende Relation X gegeben:
Produkt
Rennrad
X :=
Rennrad
Mountainbike
Preis
300
250
270
Zeit
[1, 7]
[8, 14]
[1, 20]
Dann liefert eine Gruppierung über ’Produkt’ der Form
ΓProdukt # Produkt, Summe = sum(Preis) (X)
eine Relation mit dem Schema
S 0 : {Produkt, Summe} −→ {S X (Produkt), S X (Preis)}
mit S 0 (Produkt) = S X (Produkt) und S 0 (Summe) = S X (Preis)
Schreibt man die Vereinfachungen aus, ergibt sich für den Inhalt:
I 0 = {t0 ∈ T (S 0 ) : ∃t ∈ πProdukt (X) ∧
t0 (Produkt) ∈ {x(Produkt) : x ∈ X ∧ x|Produkt = t} ∧
X
t0 (Summe) ∈ {
x(Preis) } }
{x∈X:x|Produkt =t}
14
3.2. Intervalle
Für jede der beiden durch πProdukt gegebenen Partitionen von X lassen sich die (hier
einelementigen) Ergebnismengen der Aggregationsfunktionen berechnen:
I 0 = {t0 ∈ T (S 0 ) : ∃t ∈ {(Rennrad), (Mountainbike)} = πProdukt (X) mit
t0 (Produkt) ∈ {Rennrad} ∧ t0 (Summe) ∈ {300 + 250} für Rennräder und
t0 (Produkt) ∈ {Mountainbike} ∧ t0 (Summe) ∈ {270} für Mountainbikes }
Dies entspricht der Ergebnisrelation
Produkt
Rennrad
Mountainbike
Summe
550
270
3.2. Intervalle
In diesem Abschnitt werden die Intervalle zur Modellierung des in Kapitel 2 beschriebenen Zeitstempels definiert. Zusätzlich werden Operatoren zum Umgang mit diesen
Intervallen eingeführt.
Es sei sets N = {0, 1, 2, 3, . . .} die Menge der natürlichen Zahlen.
3.2.1. Definition
Für b, e ∈ N mit b ≤ e sei das Intervall von b bis e definiert als
[b, e] := {n ∈ N : b ≤ n ≤ e}
Sei I die Menge aller so definierten Intervalle.
3.2.2. N-wertige Operatoren
Für ein Intervall I = [b, e] ∈ I gelte:
• begin(I) := b
• end(I) := e
• count(I) := end(I) − begin(I) + 1
3.2.3. Vergleichsoperatoren
Vergleichsoperatoren liefern Information über die Beziehung zweier Intervalle:
I × I −→ {wahr, falsch}
Seien also I1 := [b1 , e1 ] ∈ I und I2 := [b2 , e2 ] ∈ I zwei Intervalle.
Allens Operatoren“
”
Die folgenden Operatoren sind als Allens Operatoren“ [All83a]2 bekannt:
”
2
is_included_in wird dort during genannt, begins als starts bezeichnet und ends entsprechend
als finishes
15
3.2. Intervalle
• I1 equals(=) I2 :⇔ b1 = b2 ∧ e1 = e2
b1
• I1 is_included_in(⊆) I2 :⇔ b1 ≥ b2 ∧ e1 ≤ e2
e1
b2
• I1 before I2 :⇔ e1 < b2
b1
• I1 meets I2 :⇔ b1 = e2 + 1 ∨ b2 = e1 + 1
• I1 overlaps I2 :⇔ b1 ≤ e2 ∧ b2 ≤ e1
e2
e1
b2
e2
b1
e 1 b2
e2
b1
e1
b2
b1
• I1 begins I2 :⇔ b1 = b2 ∧ e1 ≤ e2
e2
e1
b2
e2
b1
• I1 ends I2 :⇔ e1 = e2 ∧ b1 ≥ b2
e1
b2
e2
Abgeleitete Vergleichsoperatoren
Weitere Vergleichsoperatoren sind:
• I1 after I2 :⇔ I2 before I1
• I1 includes(⊇) I2 :⇔ I2 is_included_in I1
• I1 ⊂ I2 :⇔ I1 ⊆ I2 ∧ I1 6= I2
• I1 ⊃ I2 :⇔ I1 ⊇ I2 ∧ I1 6= I2
• I1 merges I2 :⇔ I1 meets I2 ∨ I1 overlaps I2
Zusätzlich läßt sich der Spezialfall n ∈ I1 für ein n ∈ N definieren:
n ∈ I1 :⇔ [n, n] is_included_in I1 ⇔ b1 ≤ n ≤ e1
3.2.4. Intervallwertige Operatoren
Um zwei Intervalle miteinander zu einem neuen Intervall zu kombinieren, werden Operatoren der Form I × I → I benötigt. Mit I1 := [b1 , e1 ] ∈ I und I2 := [b2 , e2 ] ∈ I
sei:
•
I1 union I2 := [min (b1 , b2 ), max (e1 , e2 )] falls I1 merges I2
b1
e1
b2
e2
16
b1
e2
3.2. Intervalle
•
(
[b1 , min (b2 − 1, e1 )] falls b1 < b2 ∧ e1 ≤ e2
I1 minus I2 :=
[max (e2 + 1, b1 ), e1 ] falls b1 ≥ b2 ∧ e1 > e2
b1
e1
b2
e2
b1
b2
•
I1 intersect I2 := I1 minus (I1 minus I2 ) falls I1 overlaps I2
= [max (b1 , b2 ), min (e1 , e2 )]
b1
e1
b2
e2
b2
e1
Diese Operatoren bilden mit den obigen Bedingungen eine Algebra auf I.
3.2.5. Operatoren auf Mengen von Intervallen
Die beiden folgenden Operatoren bilden eine Teilmenge von I auf eine Teilmenge von I
ab: P(I) → P(I). Sei nun X ∈ P(I).
expand
Der Operator expand zerlegt alle übergebenen Intervalle in Einheitsintervalle (d.h. Intervalle I mit end(I) = begin(I)):
expand(X ) := {[b, b] : ∃I ∈ X ∧ b ∈ I}
Beispiel:
expand({[2, 2], [4, 6], [5, 7], [8, 9]}) = {[2, 2], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9]}
collapse
Im Gegensatz dazu verschmilzt“ collapse alle Intervalle für die dies möglich ist.
”
Beispiel:
collapse({[2, 2], [4, 6], [5, 7], [8, 9]}) = {[2, 2], [4, 9]}
= collapse(expand({[2, 2], [4, 6], [5, 7], [8, 9]}))
17
3.3. pack und unpack
Iterative Definition: Zu jedem Intervall X ∈ X sei die transitiven Hülle T ∗ (X) bezüglich merges gegeben:
T 0 (X) := {X}
T n (X) := {I ∈ X : ∃J ∈ T n−1 (X) ∧ I merges J} ∀n ∈ N≥1
T ∗ (X) := ein (beliebiges) T n (X) mit T n (X) = T n+1 (X)
Vereinigt (union) man nun alle Intervalle in jeder Hülle zu einem einzigen Intervall,
ergibt sich collapse als Vereinigung dieser Intervalle:
[
collapse(X ) :=
{ [ min
(begin(I)), max
(end(I)) ] }
∗
∗
X∈X
I∈T (X)
I∈T (X)
Deskriptive Definition:
collapse(X ) := {[b1 , e2 ] : ∃ [b1 , e1 ] ∈ X ∧ ∃ [b2 , e2 ] ∈ X
∧ b1 ≤ b2 ∧ e1 ≤ e2
∧ (¬∃I ∈ X mit I meets [b1 , e2 ])
∧ (∀n ∈ [b1 , e2 ] gilt: (∃J ∈ X mit n ∈ J))}
(1)
(2)
(3)
(4)
Erläuterung:
1: Zu jedem Intervall X in der Ergebnismenge von collapse(X ) existiert ein Intervall
[b1 , e1 ] ∈ X mit begin(X) = b1 und ein Intervall [b2 , e2 ] ∈ X mit end(X) = e2 . (Es
kann auch [b1 , e1 ] = [b2 , e2 ] sein.)
2: X wird größtmöglich gewählt; es soll gelten [b1 , e1 ] ⊆ X und [b2 , e2 ] ⊆ X.
3: Es soll kein an X angrenzendes Intervall in X existieren.
4: Für alle Elemente in X muss es ein Intervall in X geben, welches dieses Element
enthält.
Eine Entsprechung im TSQL-Konzept findet collapse im Verschmelzungsoperator
coalesce. Dieser Operator hat dort jedoch keine tiefgreifende Bedeutung und dient dazu
das Ergebnis lesbarer zu machen (vgl. etwa [Rei99a] Kapitel 3, Definition 10).
3.3. pack und unpack
Mit den nun definierten Operatoren auf Intervallen läßt sich die in 3.1 definierte Relationenalgebra um Funktionalität für Zeitstempel (bzw. Intervalle) erweitern. Hierzu werden
expand und collapse als Aggregationsfunktionen aufgefasst, damit sie auf intervallwertige Attribute einer Relation wirken können. Diese neu enstehenden Operatoren dienen
dazu eine atomare“, zeitpunktartige“ Sicht auf die Information in einer Relation zu
”
”
18
3.3. pack und unpack
erhalten (unpack), bzw. diese Information möglichst zusammengefasst“ und redun”
”
danzfrei“ betrachten zu können (pack).
Im folgenden seien X = (S, I) und Y zwei Relationen. Außerdem sei a der Name eines
intervallwertigen Attributs (a, I) von X; A := def(S) − {a} sei die Menge der Attributnamen von X ohne a und G ⊆ I eine Menge (Gruppe) von Tupeln.
3.3.1. collapse und expand als Aggregationsfunktionen
Man kann collapse und expand als Aggregationsfunktionen (nach 3.1.2) auffassen:
collapse(a) : P(I) −→ I
mit
collapse(a)(G) := collapse({t(a) : t ∈ G})
und analog
expand(a) : P(I) −→ I
mit
expand(a)(G) := expand({t(a) : t ∈ G})
3.3.2. pack und unpack für ein (einziges) Attribut
Mit diesen neuen Aggregationsfunktionen lassen sich nun pack und unpack für ein Attribut a definieren:
packa (X) := ΓA#A,a=collapse(a)
und analog
unpacka (X) := ΓA#A,a=expand(a)
Beispiel: Sei folgende Relation X gegeben:
Name
Müller
X := Müller
Schmidt
Schmidt
VT
[2, 2]
[4, 6]
[5, 8]
[8, 9]
Dann ergibt sich für den Inhalt I von
packVT (X) = ΓName # Name, VT = collapse(VT)
(vgl. das Beispiel zu Gruppierung und Aggregation in 3.1.2):
I = {t0 ∈ T (S) : ∃t ∈ πName (X) ∧
t0 (Name) ∈ {x(Name) : x ∈ X ∧ x|Name = t} ∧
t0 (VT) ∈ collapse(VT)({x ∈ X : x|Name = t}) }
19
3.3. pack und unpack
also
I = {t0 ∈ T (S) : ∃t ∈ {Müller, Schmidt} = πName (X) mit
t0 (Name) ∈ {Müller} ∧ t0 (VT) ∈ {[2, 2], [4, 6]} für Müller und
t0 (Name) ∈ {Schmidt} ∧ t0 (VT) ∈ {[5, 9]} für Schmidt }
und damit die Ergebnisrelation
Name
VT
Müller [2, 2]
packVT (X) =
Müller [4, 6]
Schmidt [5, 9]
Für unpackVT (X) ergibt sich analog das Ergebnis
Name
Müller
Müller
Müller
Müller
unpackVT (X) =
Schmidt
Schmidt
Schmidt
Schmidt
Schmidt
VT
[2, 2]
[4, 4]
[5, 5]
[6, 6]
[5, 5]
[6, 6]
[7, 7]
[8, 8]
[9, 9]
3.3.3. pack und unpack für mehrere Attribute
Sei L := l1 , . . . , ln mit n ∈ N≥1 eine (nichtleere) Liste 3 von Attributnamen:
unpackL (X) := unpackln (unpackln−1 (. . . unpackl1 (X) . . . ))
und damit
packL (X) := packln (packln−1 (. . . packl1 (unpackL (X)) . . . ))
S#
P#
Beispiel: Für X = [1, 2] [3, 4] ist
[5, 6] [7, 8]
3
keine Menge, denn für pack spielt die Reihenfolge eine Rolle
20
3.3. pack und unpack
S#
[1, 1]
[1, 1]
[2, 2]
unpackS#,P# (X) = [2, 2]
[5, 5]
[5, 5]
[6, 6]
[6, 6]
S#
[3, 5]
Mit X = [2, 4]
[2, 4]
[2, 4]
P#
[3, 3]
[4, 4]
[3, 3]
[4, 4] = unpackP#,S# (X).
[7, 7]
[8, 8]
[7, 7]
[8, 8]
P#
[1, 5]
[1, 4]
[5, 6]
[6, 9]
S#,P#
gilt pack
S#
P#
S#
P#
(X) = [2, 5] [1, 5] 6= [2, 4] [1, 9] = packP#,S# (X).
[2, 4] [6, 9]
[5, 5] [1, 5]
graphische Darstellung:
P#
P#
P#
9
9
9
8
8
8
7
7
7
6
6
6
5
5
5
4
4
4
3
3
3
2
2
2
1
1
1
2
3
4
5
S#
1
1
2
3
4
5
S#
packS#,P# (X)
X
1
2
3
4
5
S#
packP#,S# (X)
Bemerkungen:
• Für unpack spielt die Reihenfolge der Attribute in L keine Rolle, für pack dagegen
schon.
• Im allgemeinen gilt nicht
packL (X) = packln (packln−1 (. . . packl1 (X) . . . ))
Mit X wie oben im Beispiel für pack ergibt sich
21
3.4. Erweiterung der Relationenalgebra
S#
P#
packP# (packS# (X)) = packS# (packP# (X)) = [3, 5] [1, 4]
[2, 4] [1, 9]
graphisch:
P#
9
8
7
6
5
4
3
2
1
1
2
3
4
5
S#
Das anfängliche unpackL (X) ist für packL (X) also notwendig.
3.3.4. pack und unpack ohne Attribute
Um die Operatoren der Relationenalgebra zu ersetzen, wird pack sowie unpack ein Ergebnis zugewiesen, auch wenn kein Attribut angegeben ist. In diesem Fall gelte:
pack(X) := X
und auch unpack(X) := X
3.4. Erweiterung der Relationenalgebra
Mit den obigen Definitionen ist es nun möglich die Operatoren der Relationenalgebra neu
zu definieren. Sei L eine Liste von Attributnamen. L kann auch leer sein (Schreibweise:
einfach weglassen); in diesem Fall erfüllen (wegen 3.3.4) die neu definierten Operatoren
die gleiche Funktion wie die alten.
3.4.1. Dyadische Operatoren
Sei etwa die Differenz zweier Relationen X und Y neu definiert als:
X −L Y := packL (unpackL (X) − unpackL (Y ))
Natürlich müssen auch die gleichen Voraussetzungen gelten wie für die original“ Diffe”
renz, d.h. auch hier müssen X und Y das gleiche Schema haben.
Analog werden ∪L , ∩L und o
nL definiert.
22
3.4. Erweiterung der Relationenalgebra
3.4.2. Monadische Operatoren
Entsprechendes gilt für Operatoren, die auf eine einzigen Relation wirken, z.B.:
πAL (X) := packL (πA (unpackL (X)))
analog für σϕL , εLb=β und ΓLA#b1 =α1 ,...,bq =αq
(Für Umbennennungen ρb=a erscheint eine Erweiterung nicht sinnvoll, weil nur das Schema einer Relation verändert wird und nicht ihr Inhalt.)
Bemerkung: Möglicherweise wird nur das anfängliche unpack oder das abschließende
pack ausgeführt, nicht aber beides: Durch Projektion, Umbenennung oder Gruppierung
kann das in L aufgeführte Attribut entfallen (kein pack) oder erst entstehen (kein unpack).
23
4. Modellierung temporaler
Datenbanken
Für die Formulierung von Integritätsbedingungen einer temporalen Datenbank sind Begriffe notwendig, die sich auf Zeitstempel beziehen. In Abschnitt 4.1 wird erläutert, wie
solche Bedingungen mit der erweiterten Relationenalgebra beschrieben werden können.
Abhängig davon, welcher Aussage einer temporalen Datenbank ein Gültigkeitszeitraum zugeordnet sein soll, sind die Relationen entsprechend zu modellieren. Wie dabei
vorzugehen ist wird in 4.2 diskutiert.
Die besondere Bedeutung der Gegenwart führt auf die Frage wie eine Modellierung
von Zukunft und Vergangenheit erreicht werden kann (Abschnitt 4.3).
4.1. Integritätsbedingungen
Die Modellierung zeitabhängiger Daten in einem DBMS stellt zusätzliche Anforderungen
an den Zustand der Datenbank. Im folgenden werden diese Anforderungen detailliert
besprochen.
4.1.1. Eindeutige Identifikation
Wird eine bestehende Relation ohne Zeitstempel um einen solchen erweitert, sind die
bisherigen Schlüsselkandidaten1 der Relation möglicherweise nicht mehr zur eindeutigen Identifizierung ausreichend: Mehrere verschiedene Tupel in der temporal erweiterten
Relation würden nach dem nicht-temporalen Primärschlüssel2 als ein einziges Tupel
identifiziert werden, wenn sich die Werte von nicht zum Primärschlüssel gehörenden
Attributen im Laufe der Zeit verändern.
In [Kuh97a] und [Bei2001a] wird dies durch die Einführung eines zeitlich invarianten
Schlüsselsurrogats gelöst. So wird etwa eine Abteilung nicht wie in der nicht-temporalen
Version der Datenbank durch ihren Namen, sondern durch eine Nummer identifiziert,
die sich niemals ändert. Der Name einer Abteilung kann sich somit im Laufe der Zeit
ändern.
Eine weitere Möglichkeit ist, die Schlüsselkandidaten jeweils um den Zeitstempel zu
erweitern. Das hat (im Sinne des obigen Beispiels) den Vorteil, dass kein weiteres künstliches Nummer“-Attribut eingefügt werden muss und den Nachteil, dass eine Abteilung
”
keine Namensänderung durchführen darf. Allerdings sollte auch die Semantik beachtet
1
2
die minimalen Mengen von Attributen, die ein Tupel stets eindeutig identifizieren
der (aus inhaltlichen Gründen) tatsächlich zur Identifikation gewählte Schlüsselkandidat
24
4.1. Integritätsbedingungen
werden: Ist die ’Finanz’-Abteilung wirklich noch dieselbe Abteilung, sobald sie etwa in
”
’Forschung und Entwicklung’ umbenannt wird?“3
Formalisierung
Für eine Relation R ohne Zeitstempel sei A die Menge der Attributnamen von R und
K ⊆ A der Primärschlüssel. Dann kann bei einer Erweiterung von R zu R̃ um einen
Zeitstempel VT die eindeutige Identifikation erhalten werden, indem VT zum Primärschlüssel hinzugenommen wird: K̃ := K ∪ {V T }. Die vorherige Integritätsbedingung
∀r1 ∈ R : ∀r2 ∈ R : r1 |K = r2 |K ⇒ r1 = r2
wird für die neue Relation R̃ und ihren Primärschlüssel K̃ übernommen:
∀r1 ∈ R̃ : ∀r2 ∈ R̃ : r1 |K̃ = r2 |K̃ ⇒ r1 = r2
Wenn also bisher für die Einhaltung der eindeutigen Identifikation gesorgt werden konnte, sollte dies nach Erweiterung um einen Zeitstempel weiterhin möglich sein.
Bemerkung: Manchmal werden nicht alle Attribute von K̃ benötigt: Eine Teilmenge
von K̃ (etwa nur der Zeitstempel) könnte zur Identifikation von Tupeln aus R̃ genügen.
Welcher Schlüsselkandidat der richtige“ ist, hängt stets von der gewünschten Semantik
”
einer temporalen Datenbank ab.
4.1.2. Widerspruchsfreiheit
Für gewöhnlich wird davon ausgegangen, dass sich widersprechende Aussagen nicht zur
gleichen Zeit gültig sind. Die Zeitstempel inhaltlich verschiedener4 Tupel einer Relation
dürfen sich also (im Sinne von overlaps) nicht überlappen.
Da verschiedene Intervalle auch als verschiedene Werte für Zeitstempel gelten – selbst
wenn sie sich überlappen – wird diese Integritätsbedingung nicht durch die oben beschriebene Eindeutigkeitsbedingung erfüllt. Es reicht jedoch aus, die Einhaltung der
Eindeutigkeitsbedingung aus 4.1.1 für eine Relation R auch für unpackZeitstempel (R) zu
fordern:
∀r1 ∈ unpackZeitstempel (R) : ∀r2 ∈ unpackZeitstempel (R) : r1 |K = r2 |K ⇒ r1 = r2
Semantisch sind R und unpackZeitstempel (R) gleich (d.h. sie stellen die gleichen Aussagen
dar), die Einheitsintervalle in unpackZeitstempel (R) können sich aber nicht überlappen.
3
4
Nomen est omen.
d.h. es besteht ein Unterschied in mindestens einem Attribut, das nicht Zeitstempelattribut ist
25
4.1. Integritätsbedingungen
Ausnahmen
Es sind Relationen mit intervallwertigem Attribut denkbar deren Semantik verlangt,
dass Widerspruchsfreiheit nicht eingehalten wird, etwa:
Prozent während
91
[10, 15]
83
[16, 20]
72
[17, 17]
87
[10, 20]
56
[1, 24]
...
Diese Relation könnte beispielsweise die prozentuale Auslastung eines Servers beschreiben: Während des Zeitraums von 10 bis 15 Uhr betrug die durchschnittliche Auslastung
91%, von 16 bis 20 Uhr 83% um 17 Uhr 72% usf. . .
4.1.3. Zeitliche Fremdschlüssel
Eine Fremdschlüsselbeziehung von R bzgl. S ist gegeben, falls R den Primärschlüssel
von S (= Fremdschlüssel von R) enthält und zu jedem Tupel von R ein Tupel aus S mit
den gleichen Werten in all diesen Schlüsselattributen existiert ( R referenziert S“).
”
Analog zu 4.1.2 gilt: Wenn der Fremdschlüssel den Zeitstempel enthält, wird diese Integritätsbedingung nicht durch die Eindeutigkeitsbedingung erfüllt. Es reicht jedoch aus
die Fremdschlüsselbeziehung für unpackZeitstempel (R) bzgl. unpackZeistempel (S) zu fordern
(siehe Bemerkung zu 4.2.2 für ein Beispiel).
4.1.4. Redundanzfreiheit
Redundanz tritt in temporalen Datenbanken auf, wenn sich die Zeitstempel inhaltlich
gleicher5 Tupel überlappen: Die zu den Zeitpunkten in der Schnittmenge gehörenden
Aussagen werden durch mehrere Tupel ausgedrückt. Ausserdem sind verschiedene Aussagen redundant, wenn sie sich durch eine einzige ausdrücken lassen. Dies ist der Fall,
wenn inhaltlich gleiche Tupel aneinandergrenzende (im Sinne von meets) Zeitstempel
haben. Durch die Vereinbarung die temporale Relation R stets gepackt zu halten“ so
”
dass stets
R = packZeitstempel (R)
gilt, wird diese Redundanz vermieden.
Ist eine Relation mit mehr als einem intervallwertigen Attribut (etwa in einer bitemporalen Datenbank) redundanzfrei im obigen Sinn, dann enthält sie nicht notwendigerweise
die minimale Anzahl von Tupeln. Umgekehrt folgt aus der minimalen Tupelanzahl einer
Relation im allgemeinen nicht die Redundanzfreiheit.
5
d.h. es besteht kein Unterschied zwischen allen Attributen, die nicht Zeitstempelattribut sind
26
4.1. Integritätsbedingungen
Beispiel
R enthält mit den beiden Tupeln ([3, 8], [1, 4]) und ([5, 9], [3, 8]) die redundante Aussage
([5, 8], [3, 4]). Die gepackten“ Relationen enthalten keine Redundanz mehr:
”
P#
9
8
7
S#
P#
[3, 8] [1, 4]
R=
[5, 9] [3, 8]
[1, 7] [7, 9]
6
5
4
3
2
1
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
S#
P#
9
S#
[3, 8]
[3, 9]
packS#, P# (R) =
[5, 9]
[1, 9]
[1, 7]
8
P#
[1, 2]
[3, 4]
[5, 6]
[7, 8]
[9, 9]
7
6
5
4
3
2
1
S#
P#
9
S#
[3, 4]
[1, 4]
packP#, S# (R) =
[5, 7]
[8, 8]
[9, 9]
8
P#
[1, 4]
[7, 9]
[1, 9]
[1, 8]
[3, 8]
7
6
5
4
3
2
1
S#
Ausnahmen
Es sind Relationen mit Zeitstempel denkbar deren Semantik verlangt, dass Redundanzfreiheit nicht eingehalten wird, beispielsweise:
27
4.1. Integritätsbedingungen
Präsident
Ford
Carter
Reagan
Reagan
Clinton
Clinton
Jahre
[1974, 1976]
[1977, 1980]
[1981, 1984]
[1985, 1988]
[1993, 1996]
[1997, 2000]
...
Für diese Relation, als Liste von amerikanischen Präsidenten und den dazugehörigen
Amtszeiten, mag es sinnvoll sein sie nicht gepackt zu halten“, um anzudeuten wieviele
”
Legislaturperioden jeder Präsident im Amt war.
4.1.5. Stetigkeit
Weitere weniger elementare Integritätsbedingungen sind selbstverständlich denkbar und
mit der erweiterten Relationenalgebra formulierbar.
Eine nicht explizit in [DDL2003a] behandelte Integritätsbedingung ist etwa die Forderung nach der Stetigkeit temporaler Daten, d.h. der modellierte zeitlichen Ablauf darf
keine Lücken aufweisen.
Formalisierung
Sei K der Primärschlüssel von R. Dann sei K̃ := K − {Zeitstempel} die Menge der
Primärschlüsselattribute ohne Zeitstempel.
Zeitstempel
R ist stetig falls K̃ ein Schlüsselkandidat für πK
(R) ist. Ist der Zeitstempel das
Zeitstempel
einzige Primärschlüsselattribut, muss πK
(R) aus genau einem Tupel bestehen.
Beispiel
Sei {Name, VT)} der Primärschlüssel von R.
Name
Gehalt
VT
Name
VT
Albers
6000
[1, 60]
Müller
3000 [10, 20]
Albers
[1, 60]
VT
(R)
=
Mit R := Schmidt 3000 [21, 30] ist πName,
Müller
[10,
20] .
VT
Schmidt 4000 [31, 50]
Schmidt [21, 50]
Müller
4000 [51, 60]
Müller [51, 70]
Müller
5000 [61, 70]
VT
Da ’Müller’ in πName,
VT (R) zweimal auftaucht, ist der Name hier kein Schlüsselkandidat
und damit R nicht stetig. Allerdings wäre R stetig, wenn ’Schmidt’ in ’Müller’ (oder
umgekehrt) umbenannt würde.
28
4.2. Tupel- oder Attributzeitstempel
4.2. Tupel- oder Attributzeitstempel
Die Betrachtung von Relationen mit Tupeln deren Attributwerte in einer gewissen Zeitspanne konstant bleiben führt zu der Frage, wie solche Relationen zu modellieren sind.
Denn wird der Wert eines Attributs häufig verändert, die Werte der anderen Attribute
aber kaum, so entstehen viele Tupel, die sich inhaltlich nur in einem einzigen Attribut
unterscheiden.
Eine Lösung wäre, für einzelne Gruppen von Attributen deren Werte gemeinsam verändert werden, eigene Zeitstempel einzuführen – Zeitstempel auf Attributen (Attribute
Timestamping) im Gegensatz zu Zeitstempeln auf Tupeln (Tupel Timestamping).
Die Einführung weiterer Zeitstempel in dieselbe Relation würde aber selbstverständlich
das Problem nur verschlimmern. Es ist also notwendig die Ausgangsrelation in mehrere
Relationen aufzuteilen: In [DDL2003a] wird vorgeschlagen für jedes Attribut eine eigene
Relation zu modellieren. Ändern sich Attribute stets synchron, wäre es jedoch unnötig wenn diese Attribute jeweils eigene Relationen erhielten. Jede Gruppe von synchron
veränderlichen Attributen kann also in je einer einzigen Relation modelliert werden.
Damit diese Relationen wieder ohne Informationsverlust zur Ausgangsrelation zusammengefügt werden können, müssen sie jeweils den Primärschlüssel (also nach 4.1.1 auch
einen Zeitstempel) enthalten. Die Rekonstruktion kann dann über den erweiterten Verbund (o
nZeitstempel ) geschehen.
Für die beschriebene Zerlegung gelten die Vor- und Nachteile einer Normalisierung:
Anfragen bezüglich des Zeitstempels eines bestimmten Attributs können anhand der
weniger umfangreichen Teilrelation beantwortet werden. Aufgrund der zusätzlich benötigten Verbunde verringert sich jedoch die Ausführungsgeschwindigkeit von Anfragen,
die sich nun auf mehrere Relationen beziehen müssen.
Es mag allgemein für die zugrundeliegende Semantik vorteilhaft sein, die durch die
ursprüngliche Relation modellierten Aussagen in mehrere kürzere, prägnantere aufzuteilen. Die Modellierung bestimmter Aussagen kann durch die Zerlegung erst möglich
werden (vgl. Bemerkungen zum Beispiel).
4.2.1. Formalisierung
Sei R eine Relation mit Attributmenge A und sei {A1 , . . . , An } ⊂ P(A) eine Menge von
Teilmengen der Attribute. Weiterhin sei L eine Liste intervallwertiger Attribute von R
– für eine temporale Datenbank also das Zeitstempelattribut: L = Zeitstempel.
• R erfüllt die Join-Abhängigkeit ∗(A1 , . . . , An ) sofern stets gilt:
R = πAL1 (R) o
nL · · · o
nL πALn (R)
(Ist L die leere Liste, entspricht dies der klassischen Definition der Join-Abhängigkeit.)
• Eine Join-Abhängigkeit heißt trivial, falls ein Ai die gesamte Attributemenge von
R ist, also Ai = A für ein 1 ≤ i ≤ n gilt.
29
4.2. Tupel- oder Attributzeitstempel
• Eine nicht-triviale Join-Abhängigkeit ∗(A1 , . . . , An ) sei hier als kollektiv bezeichnet, falls stets gilt:
R = πAL1 (R) o
n ··· o
n πALn (R)
Enthält jedes Ai (1 ≤ i ≤ n) alle Attribute aus L, so kann R im allgemeinen nur genau dann über den klassischen Join-Operator wieder verlustlos aus
den Projektionen zusammengesetzt werden, wenn jedes πALi (R) die Werte aller
L-Attribute unverändert läßt, also stets πALi (R) = πAi (R) gilt. Im temporalen
Kontext (L = Zeitstempel) bedeutet dies eine synchrone Änderung der Attribute.
Dieser Begriff wird bedeutungslos, falls L die leere Liste ist.
• Die Zerlegung von R in Projektionen πAL1 (R), . . . , πALn (R) wird vertikale Dekomposition (von R) genannt. (L kann auch die leere Liste sein.)
• Eine Relation R ist genau dann in der sechsten Normalform (6NF), wenn sie keine
nicht-trivialen Join-Abhängigkeit erfüllt. (Der Begriff 6NF“ bezieht sich auf die
”
gebräuchliche Projection/Join-Normalform, welche mit 5NF abgekürzt wird (siehe
Bemerkung). Für einen tieferen Einblick in die Normalisierungstheorie siehe z.B.
[Fag79] oder [Dat2000a].)
Um nun Zeitstempel für Attribute zu modellieren, ist es hinreichend die 6NF für jede
Relation der temporalen Datenbank zu fordern. Für jede Relation, die nicht in 6NF ist,
kann die durch eine nicht-triviale Join-Abhängigkeit vorgegebene vertikale Dekomposition durchgeführt werden, bis alle Relationen diese Forderung erfüllen.
Allerdings erscheint es unnötig eine Relation R entsprechend zu zerlegen, falls sich
Attribute stets synchron verändern. Dies ist der Fall, wenn R eine kollektive JoinAbhängigkeit erfüllt.
Bemerkung: Jede Relation in 6NF ist auch in Projection/Join-Normalform (5NF).
Diese ist über die klassische Join-Abhängigkeit (also mit π und o
n statt π L und o
nL )
definiert. Für 5NF wird gefordert, dass jede nicht-triviale Join-Abhängigkeit erfüllt, auf
einen Schlüsselkandidaten von R zurückgeht.
4.2.2. Beispiel
Nr
Name
Gehalt ChefNr
VT
2
Albers
6000
2
[1, 60]
10 Müller
3000
7
[10, 20]
R := 10 Schmidt 3000
7
[21, 30]
10 Schmidt 4000
2
[31, 50]
10 Müller
4000
2
[51, 60]
10 Müller
5000
1
[61, 70]
30
4.2. Tupel- oder Attributzeitstempel
Da zu jedem Zeitpunkt einem Angestellten genau ein Name, ein Gehalt und ein Chef
zugeordnet werden, besteht der Primärschlüssel hier aus den Attributen ’Nr’ und ’VT’.
R erfüllt die nicht-triviale Join-Abhängigkeit
∗({Nr, Name, VT}, {Nr, Gehalt, ChefNr, VT})
Damit ist R nicht in 6NF (jedoch in 5NF). Für die Projektion
Nr
Name
VT
2
Albers
[1, 60]
VT
πNr,
Müller [10, 20]
Name, VT (R) = 10
10 Schmidt [21, 50]
10 Müller [51, 70]
existieren keine nicht-trivialen Join-Abhängigkeiten – sie ist in 6NF. Hingegen erfüllt die
Projektion
Nr Gehalt ChefNr
VT
2
6000
2
[1, 60]
VT
πNr,
3000
7
[10, 30]
Gehalt, ChefNr, VT (R) = 10
10
4000
2
[31, 60]
10
5000
1
[61, 70]
die Join-Abhängigkeit
∗({Nr, Gehalt, VT}, {Nr, ChefNr, VT})
ist also nicht in 6NF.
Unter der (zugegeben unrealistischen) Annahme, dass Gehalt und ChefNr stets gemeinsam (also synchron) verändert werden, ist diese Join-Abhängigkeit jedoch kollektiv.
Die Zerlegung von R in die obigen beiden Projektionen ermöglicht dann eine Modellierung von Zeitstempeln für die Attribute VT sowie Gehalt synchron mit ChefNr.
Ansonsten kann R anhand dieser (nicht kollektiven) Join-Abhängigkeit aufgeteilt werden:
∗({Nr, Name, VT}, {Nr, Gehalt, VT}, {Nr, ChefNr, VT})
Die genannten Zerlegungen sind natürlich nur dann sinnvoll, wenn die entsprechenden
Join-Abhängigkeiten für jede semantisch mögliche Ausprägung von R gelten und nicht
nur für diese konkreten Werten.
Bemerkungen:
• Durch die Zerlegung können getrennte Aussagen über Name und Gehalt/ChefNr
getroffen werden – etwa könnte der Namen eines Angestellten für einem bestimmten Zeitpunkt bekannt sein, das Gehalt (und der Chef) jedoch nicht.
Ist das nicht erwünscht, wäre eine zeitliche Fremdschlüsselbeziehung notwendig:
VT
Zu jedem Tupel aus unpack(πNr,
Name, VT (R)) muss ein Tupel aus
VT
unpack(πNr, Gehalt, ChefNr, VT (R)) mit gleichen Werten für Nr und VT existieren.
31
4.3. Zukunft, Gegenwart und Vergangenheit
• Allein von der konkreten Anzahl der Beispieltupel ausgehend, lohnt sich die Dekomposition hier nicht – 8 Tupel in zwei Relationen statt 6 Tupel in einer Relation.
Im allgemeinen Fall kann sich das natürlich ändern.
• Eine weitere nicht-triviale Join-Abhängigkeit die R offensichtlich erfüllt ist:
∗({Nr, VT}, {Nr, Name, VT}, {Nr, Gehalt, ChefNr, VT})
VT
Ob es zweckmäßig ist durch die zusätzliche Relation πNr,
VT (R) explizit zu materialisieren wie lange eine Person angestellt ist, kann nicht allgemein entschieden
werden (vgl. die Relationen S, SS und SP in 5.2.1).
4.3. Zukunft, Gegenwart und Vergangenheit
Wird an den Zeitstempel einer Relationen keine besondere zeitliche Bedingung gestellt,
so kann die Aussage eines Tupels für beliebige Zeiträume in Zukunft, Gegenwart oder
Vergangenheit gelten.
Ist das Ende der Gültigkeit einer Aussage nicht abzusehen, wird ein künstlicher bis”
auf-weiteres“-Wert benötigt. Ebenso müsste ein ∞“-Wert für ewig“ geltende Aussagen
”
”
existieren, oder zumindest durch den spätesten darstellbaren Zeitpunkt angenähert werden können. Diese Konstrukte können jedoch zu logischen und semantischen Komplikationen führen (vgl. [DDL2003a] Kapitel 10.5).
Eine weitere Möglichkeit mit unbekannten Gültigkeitszeiträumen umzugehen, ist diese gar nicht erst zu modellieren: Aussagen können in historische“ (für die der Gül”
tigkeitszeitraum bekannt ist) und aktuelle“ (für die noch nicht feststeht wann ihre
”
Gültigkeit endet) aufgeteilt werden. Für historische Aussagen wird wie bisher die ( voll”
temporale“) Modellierung durch Relationen mit Zeitstempelintervall genutzt. Die ( semi”
temporalen“) Relationen für aktuelle Aussagen enthalten dagegen kein ganzes Intervall
als Zeitstempel, sondern nur den Zeitpunkt des Beginns der Gültigkeit. Steht das Ende
der Gültigkeit einer aktuellen Aussage fest, wird das entsprechende Tupel mit dem nun
bekannten Gültigkeitszeitraum in die historischen Relationen übernommen und aus den
Relationen für aktuelle Daten entfernt.
Diese Modellierung hat den Vorteil auf die Einführung der oben genannten speziellen
Werte verzichten zu könnnen. Der Nachteil liegt in der zusätzlichen Anzahl von Relationen die durch die Partitionierung nach der Zeit (also durch die zeitliche horizontale
Dekomposition) entstehen. Anfragen, für die keine Unterscheidung nach aktuell“ und
”
historisch“ erwünscht ist, sind dann meist umständlicher zu formulieren.
”
Anmerkungen:
• Es ist natürlich möglich zukünftige Aussagen bei denen der Gültigkeitszeitraum
feststeht“ ebenso durch eigene Relationen wie die historischen Aussagen zu mo”
dellieren. Allerdings kann nicht automatisch vom DBMS festgestellt werden, wann
32
4.3. Zukunft, Gegenwart und Vergangenheit
eine die Zukunft betreffende Aussage gilt und wann nicht6 .
• Hier wird eine Zeitrichtung von Vergangenheit“ nach Zukunft“ unterstellt, da
”
”
angenommen wird, dass der End zeitpunkt der Gültigkeit einer Aussage häufig
unbekannt ist. Die umgekehrte Richtung (etwa wenn in einer archäologischen Datenbank der Beginn unbekannt ist) läßt sich offensichtlich analog modellieren.
Beispiel
Ist R die Relation aus Beispiel 4.2.2 und jetzt“ der Zeitpunkt 52, dann ergibt sich:
”
Nr
Name
Gehalt ChefNr
VT
2
Albers
6000
2
[1, bis-auf-weiteres]
10 Müller
3000
7
[10, 20]
R :=
10 Schmidt 3000
7
[21, 30]
10 Schmidt 4000
2
[31, 50]
10 Müller
4000
2
[51, bis-auf-weiteres]
und mit horizontaler Dekomposition:
Raktuell
RHistorie
Nr Name Gehalt ChefNr VT
:= 2 Albers 6000
2
1
10 Müller 4000
2
51
Nr
Name
Gehalt ChefNr
VT
10 Müller
3000
7
[10, 20]
:=
10 Schmidt 3000
7
[21, 30]
10 Schmidt 4000
2
[31, 50]
Die nächste Veränderung findet zum Zeitpunkt 61 statt: ’Albers’ scheidet aus und ’Müller’ bekommt ein höheres Gehalt und einen neuen Chef. Die entprechenden Tupel werden
in die Historie übernommen.
Nr
Name
Gehalt ChefNr
VT
2
Albers
6000
2
[1, 60]
10 Müller
3000
7
[10, 20]
R := 10 Schmidt 3000
7
[21, 30]
10 Schmidt 4000
2
[31, 50]
10 Müller
4000
2
[51, 60]
10 Müller
5000
1
[61, bis-auf-weiteres]
mit horizontaler Dekomposition:
6
Wenn es im Jahre 1879 schon Computer gegeben hätte, würden diese vorausgesagt haben, dass man
”
Infolge der Zunahme von Pferdewagen im Jahre 1979 im Pferdemist ersticken würde.“ (John C.
Edwards)
33
4.3. Zukunft, Gegenwart und Vergangenheit
Raktuell :=
RHistorie
Nr Name Gehalt ChefNr VT
10 Müller 5000
1
61
Nr
Name
Gehalt ChefNr
VT
2
Albers
6000
2
[1, 60]
10 Müller
3000
7
[10, 20]
:=
10 Schmidt 3000
7
[21, 30]
10 Schmidt 4000
2
[31, 50]
10 Müller
5000
1
[61, 70]
Anfragebeispiele: Um die Frage nach den Namen der aktuell angestellten Personen zu
beantworten, ist nun kein jetzt- oder bis-auf-weiteres-Wert mehr nötig, es genügt
schlicht:
πName (Raktuell )
im Gegensatz zu
πName (σjetzt∈VT (R))
wobei zusätzlich darauf zu achten ist, dass etwa gilt jetzt ∈ [1, bis-auf-weiteres].
Wird allerdings die Frage Wie lauten die Namen aller jemals angestellten Personen?“
”
gestellt, ist die Anfrage an die zwei Relationen Raktuell und RHistorie komplizierter:
πName (Raktuell ) ∪ πName (RHistorie )
im Gegensatz zu
πName (R)
34
Der Tag ist 24 Stunden lang, aber unterschiedlich breit.
(unbekannt)
5. Pragmatik – Anfragebeispiele
In diesem Kapitel wird versucht eine gewisse Pragmatik (Erfahrung, Gefühl“) im Um”
gang mit der erweiterten Relationenalgebra aufzubauen. Hierfür werden Anfragen an
temporale Datenbanken aus verschiedenen Quellen in der neuen Algebra formuliert.
Dadurch wird eine Erprobung der Ausdrucksfähigkeit der Algebra ermöglicht. Außerdem wird ein Vorrat an Beispielen zur Veranschaulichung der Modellierung und zum
besseren Verständnis von Optimierung und Realisierung angeboten.
5.1. Beispiele aus [Bei2001a] – ein Vergleich mit TSQL2
Die in [Bei2001a] beschriebene objekt-relationale Realisierung einer temporalen Datenbanksprache basiert auf dem z.B. in [Sno95a] beschriebenen TSQL2-Ansatz. Statt der
dort verwendeten temporalen Elemente wird in dieser Arbeit ein intervallwertiges Zeitstempelattribut verwendet (siehe 2.2.3).
Um mit TSQL2 vergleichen zu können, wird im folgenden zuerst die entsprechende
TSQL2-Anfrage angegeben. Hierbei sind einige syntaktische Besonderheiten zu beachten:
temporale Aufwärtskompatibilität: Dieses Konzept führt dazu, dass Anfragen ohne spezielle Kennzeichnung durch das validtime-Schlüsselwort nur auf dem aktuellen
Datenbestand (von heute“) arbeiten. Eine validtime-Anfrage liefert stets das
”
Attribut mit dem Zeitstempel zurück, sofern sie nicht als nonsequenced gekennzeichnet ist1 .
sequenced: Die Operatoren einer mit sequenced gekennzeichneten Anfrage wirken nur
auf Tupel, die im gleichen Zeitraum gültig sind. Mit nonsequenced gibt es keine
Einschränkungen. Die Angabe von sequenced nach validtime kann entfallen.
coalesce: entspricht etwa einem pack auf das Zeitstempelattribut. (Es dient jedoch
lediglich dazu das Ergebnis einer Anfrage besser lesbar zu machen.)
5.1.1. Beispieldatenbank
Nr Name Gehalt ChefNr
ang:= 12 Müller 5000
27
...
1
VT
[3, 7]
In TSQL2 sind temporale (mit verstecktem Zeitstempel) und nicht-temporale Tabellen (ohne Zeitstempel) zwei verschiedene, nicht immer miteinander vereinbare Arten von Tabellen.
35
5.1. Beispiele aus [Bei2001a] – ein Vergleich mit TSQL2
Der Name der Beispielrelation ist ’ang’ – mit der offensichtlichen Semantik für Daten
von Angestellten. In diesem Sinn sind die Tupel aus ’ang’ eindeutig durch ’Nr’ und den
Zeitstempel ’VT’ identifiziert. Da in [Bei2001a] der Zeitstempel jedoch versteckt ist, wird
dort zu diesem Zweck das (ebenfalls versteckte) Schlüsselsurrogat ’RWO’ eingeführt.
Das Attribut ’Nr’ dient der Unterscheidung von Angestellten gleichen Namens. Im
folgenden sei der Einfachheit halber angenommen, dass es keine Namensvettern in ’ang’
gibt.2
5.1.2. Anfragebeispiele
Wie lauten die Daten der derzeit angestellten Personen?
SELECT * FROM ang
Sei heute ∈ N die aktuelle Zeit, dann ist die Anfrage formulierbar als:
σheute∈VT (ang)
Es werden alle Tupel ausgewählt, deren Zeitstempel die aktuelle Zeit enthalten.
Wie lautet der Beschäftigungszeitraum eines Angestellten?
VALIDTIME SELECT x.name, VALIDTIME(x.RWO) FROM ang x
validtime wird hier auf ein Attribut angewandt und liefert laut [Bei2001a] den zum
”
größtmöglichem Intervall erweiterten Gültigkeitszeitraum des Attributs“ zurück.
VT
πName,
VT (ang)
Um den Beschäftigungszeitraum zu erhalten, werden nur der Name (und der zugehörige
VT
eingebettete pack sorgt dann
Zeitstempel) eines Angestellten projiziert. Das in π...
dafür, dass der größtmögliche (zusammenhängende) Zeitraum ausgegeben wird.
In welchen Zeiträumen war das Gehalt eines Angestellten konstant?
NONSEQUENCED VALIDTIME SELECT x.name, VALIDTIME(x.gehalt) FROM ang x
VT
πName, VT (πName,
Gehalt, VT (ang))
Wie oben werden wieder die für diese Anfrage unwichtigen Attribute durch die Projektion ausgeblendet und dann die Zeitstempel (durch pack) entsprechend zusammengefasst.
Wer verdient(e) wann mehr als 5250?
VALIDTIME COALESCE SELECT name FROM ang WHERE gehalt > 5250
VT
πName,
VT (σGehalt>5250 (ang))
Die Tupel aus ’ang’ mit einem Gehaltswert größer 5250 werden ausgewählt und dann
der größtmögliche Zeitraum für jeden Namen ausgegeben.
2
sonst ist überall wo nach einem Angestellten gefragt ist, zusätzlich dessen Nummer auszugeben
36
5.1. Beispiele aus [Bei2001a] – ein Vergleich mit TSQL2
Wer verdient(e) mehr als sein Chef und wie heißt/hieß der Chef?
VALIDTIME SELECT x.name, y.name FROM ang x, ang y
WHERE x.chefnr = y.nr AND x.gehalt > y.gehalt
Mit
X := ρX.Nr = Nr, X.Name = Name, X.Gehalt = Gehalt, X.ChefNr = ChefNr (ang) und
Y := ρY.Nr = Nr, Y.Name = Name, Y.Gehalt = Gehalt, Y.ChefNr = ChefNr (ang)
ergibt sich
πX.Name, Y.Name (σX.ChefNr = Y.Nr ∧ X.Gehalt > Y.Gehalt (X o
nVT Y ))
Durch den verwendeten erweiterten Join wird zunächst ein unpack auf das Zeitstempelattribut von X und Y durchgeführt. Die so entstandenen Einheitsintervallen der betrachtete Zeitraum von Angestellten (X) und Chefs (Y) werden dann durch o
nVT auf
Gleichheit geprüft: X.VT = Y.VT.
Welche Angestellten haben jemals eine Gehaltserhöhung erhalten?
NONSEQUENCED VALIDTIME SELECT x.name FROM ang x, ang y
WHERE x.name = y.name AND x.gehalt < y.gehalt
AND END(VALIDTIME(x)) = BEGIN(VALIDTIME(y))
(VALIDTIME(x) = x.VT und VALIDTIME(y) = y.VT – denn VT ist verstecktes Attribut)
Mit
X := ρX.Nr = Nr, X.Gehalt = Gehalt, X.ChefNr = ChefNr, X.VT = VT (ang) und
Y := ρY.Nr = Nr, Y.Gehalt = Gehalt, Y.ChefNr = ChefNr, Y.VT = VT (ang)
ergibt sich
πName (σX.VT before Y.VT ∧ X.Gehalt < Y.Gehalt (X o
n Y ))
Hat ein Angestellter eine Gehaltserhöhung bekommen, so müssen zwei Tupel in ’ang’
existieren, die seine Gehaltsdaten vor (X) und nach (Y) der Erhöhung repräsentieren.
Solche Tupelpaare werden ausgewählt und der zugehörige Name des Angestellten ausgegeben.
Wie lauteten/lauten alle Angestelltendaten, falls jemand jemals 5500 verdient
hat?
VALIDTIME COALESCE SELECT * FROM ang WHERE EXISTS ANYTIME(
VALIDTIME COALESCE SELECT * FROM ang WHERE gehalt = 5500)
Hat ein Angestellter irgendwann 5500 verdient, so ist die Relation σGehalt=5500 (ang) nichtleer. Mit der konstanten Selektionsfunktion
ϕ = σGehalt=5500 (ang) 6= ∅
entspricht die Anfrage dem Term σϕ (ang) der erweiterten Relationenalgebra. Es werden
also entweder alle Angestelltendaten ausgegeben oder keine.
37
5.2. Beispiele aus [DDL2003a]
Wie lauteten/lauten alle Angestelltendaten, als jemand 5500 verdient hat?
VALIDTIME COALESCE SELECT * FROM ang WHERE EXISTS SOMETIME(
VALIDTIME COALESCE SELECT * FROM ang WHERE gehalt = 5500)
Die Unteranfrage“ in TSQL2 kann durch einen Join entschachtelt werden:
”
Xo
nVT Y mit
mit Y :=πVT (σGehalt = 5500 (ang)) und X := ang
5.2. Beispiele aus [DDL2003a]
In [DDL2003a] werden zunächst temporal-relationale Operatoren in einer beispielhaften
Sprache ( Tutorial D“) definiert, an denen sich die hier vorgestellte erweiterte Relationen”
algebra anlehnt. Kapitel 13 beinhaltet Beispielanfragen an eine Temporale Datenbank.
5.2.1. Beispieldatenbank
Die Beispiele beziehen sich auf drei Relationen:
S# during
2
[2, 4]
...
Relation S:
Diese Relation stellt die Vertragslaufzeit (during) eines Zulieferers (S# – supplier) dar
– also hier: Zulieferer 2 ist (oder war oder wird sein) von 2 bis 4 unter Vertrag.“
”
S# Status during
Relation SS: 2
5
[2, 2]
...
Hier wird der Status den ein Zulieferer in einem bestimmten Zeitraum hat/hatte vermerkt: Zulieferer 2 hat den Status 5 zum Zeitpunkt 2.“
”
S# P# during
Relation SP: 2
1
[2, 3]
...
In SP wird angegeben welche Teile (P# – part) ein Zulieferer in welchem Zeitraum liefern
kann: Zulieferer 2 kann Teil 1 von 2 bis 3 liefern.“
”
5.2.2. Anfragebeispiele
Wie lautet der Status des Zulieferers ’1’ zum Zeitpunkt n?
Dies läßt sich für ein n ∈ N formulieren als
πStatus (σS#=’1’ ∧ n ∈ during (SS))
38
5.2. Beispiele aus [DDL2003a]
Welche Zulieferer konnten im gleichen Zeitraum die beiden Teile ’1’ und ’2’
liefern?
Ist bekannt wann ein Zulieferer ’1’ liefern kann
X := πS#, during (σP#=’1’ (SP ))
und entprechend wann ein Zulieferer ’2’ liefern kann
Y := πS#, during (σP#=’2’ (SP ))
liefert ein erweiterter Verbund das gesuchte Ergebnis:
πS# (X o
nduring Y )
Welche Zulieferer konnten nie im gleichen Zeitraum die beiden Teile ’1’ und ’2’
liefern?
Ist X die Ergebnisrelation aus dem vorigen Beispiel, dann entspricht die Anfrage dem
Term
πS# (S) − X
In welchen Zeiträumen konnte ein Zulieferer keine Teile liefern?
S −during πS#, during (SP )
Welche Zulieferer konnten wann welche Teile liefern?
Für die geforderte Übersicht erscheint es sinnvoll nicht nur die Zeiträume, sondern auch
die Teile als Intervall auszugeben. Hierzu wird zunächst ein Einheitsintervall für jedes
Teil gebildet. Die größtmöglichen Intervalle werden dann ausgegeben.
during, parts
πS#,
parts, during (parts=[P#,P#] (SP ))
In welchen Zeiträumen war mindestens ein Zulieferer unter Vertrag?
during
πduring
(S)
Durch die Verwendung der erweiterten Projektion erhält man die größtmöglichen Zeiträume.
In welchen Zeiträumen war kein Zulieferer unter Vertrag?
Sei C eine Relation mit dem intervallwertigen Attribut ’during’, welche das Tupel [0, max]
enthält, wobei max der letzte darstellbare Zeitpunkt ist. Damit ergibt sich das Ergebnis
C −during πduring (S)
39
5.3. Beispiele zu Gruppierung und Aggregation
Welche Zulieferer, die schon mal unter Vertrag waren, sind heute erneut unter
Vertrag?
Sei heute ∈ N die aktuelle Zeit. Unter der Annahme, dass jedes Tupel in S einem eigenen
Vertrag entspricht (vgl. 4.1.4), ist die Anfrage formulierbar als:
πS# (σheute∈during (S)) o
n πS# (σheute>end(during) (S))
Wie lauten die Paare von (verschiedenen) Zulieferern, die zum selben Zeitpunkt
einen (neuen) Status zugewiesen bekamen?
Geht man davon aus, dass SS = packduring (SS) gilt, lautet der entsprechende Ausdruck
in der Relationenalgebra:
πX.S#, Y.S# (σbegin(X.during) = begin(Y.during) ∧ X.S# < Y.S# (X o
n Y ) mit
X := ρX.S# = S#, X.during = during (SS) und
Y := ρY.S# = S#, Y.during = during (SS)
Bemerkung: Geht man nicht von der Annahme aus, dass SS stets gepackt“ gehalten
”
wird, wäre eine kompliziertere Formulierung nötig: Es müsste festgestellt werden, ob
für ein Tupel aus X (bzw. Y ) eine Veränderung des Status bezüglich des vorherigen
Zeitpunkts vorliegt.
5.3. Beispiele zu Gruppierung und Aggregation
Die bisher betrachteten Quellen bieten wenig Beispiele für gruppierende oder aggregierende Anfragen. Um die Auswirkung von den in die erweiterte Relationenalgebra
eingebetteten Operatoren pack und unpack auf solche Anfragen beurteilen zu können,
erscheinen weitere Beispiele sinnvoll.
5.3.1. Beispieldatenbank
Produkt
Rennrad
Rennrad
Relation R:
Rennrad
Mountainbike
Mountainbike
Preis
300
250
270
270
240
Hersteller
Produkt
Teua
Rennrad
Shnel
Rennrad
Relation S:
Teua
Rennrad
Shnel
Mountainbike
Robus
Mountainbike
40
Zeit
[1, 7]
[8, 14]
[15, 25]
[1, 20]
[21, 30]
Zeit
[1, 7]
[8, 20]
[21, 25]
[1, 10]
[11, 30]
5.3. Beispiele zu Gruppierung und Aggregation
5.3.2. Anfragebeispiele
Was ist der höchste Preis pro Produkt?
ΓProdukt # Produkt, Höchstpreis = max(Preis) (R)
Eine Formulierung mit dem erweiterten Operator ΓZeit
... führt zum gleichen Ergebnis, denn
das Maximum ist von der Anzahl der Tupel einer Gruppierung unabhängig: unpackZeit (R)
enthält zwar mehr Tupel als R, jedoch bleibt der Wertebereich von ’Preis’ gleich.
Was ist der Höchstpreis pro Produkt und wann wird er angenommen?
Ist X das Ergebnis aus obiger Anfrage, dann lassen sich die gesuchten Tupel mit einem
natürlichen Verbund aus R herausfiltern:
Ro
n (ρ Höchstpreis = Preis (X))
Eine Formulierung mit o
nZeit würde bewirken, dass überlappende Zeitbereiche mehrerer
Maxima zusammengefasst werden.
Wieviele verschiedene Produktpreise pro Hersteller gibt es?
Diese Anfrage soll etwa für den Hersteller ’Shnel’ das Ergebnis ’2’ liefern: Er hat Rennräder im Zeitraum [8, 14] zum Preis ’250’ und im Zeitraum [15, 20] zum Preis ’270’ sowie
Mountainbikes im Zeitraum [1, 10] zum Preis ’270’ hergestellt. Das sind genau zwei verschiedene Produktpreise.
ΓHersteller # Hersteller, Anzahl = count (πHersteller, Preis (R o
nZeit S))
Zunächst wird die Beziehung von Hersteller und Preis über den Fremdschlüssel (bestehend aus Produkt und Zeit) durch die Verwendung eines erweiterten Verbunds hergestellt. Da nicht nach Produkt (sondern nur nach Preis) unterschieden werden soll und
der Zeitraum hier ebenfalls uninteressant ist, wird das Ergebnis auf Hersteller und Preis
eingeschränkt.
Wie hoch ist der Durchschnittspreis pro Produkt?
Bei dieser Frage ist zu präzisieren auf welchen Zeitraum sich die Bildung des Durchschnitts beziehen soll:
ΓProdukt # Produkt, Durchschnitt = avg(Preis) (R)
= 255 als Durchschnittspreis für Mountainbikes, wobei sich der
liefert etwa 270+240
2
Durchschnitt auf die zwei Tupel in R bezieht. Andererseits liefert
ΓZeit
Produkt # Produkt, Durchschnitt = avg(Preis) (R)
270∗20+240∗10
20+10
= 260 als Durchschnittspreis für Mountainbikes, wobei der Preis ’270’ mit
20 Zeiteinheiten ins Gewicht fällt und ’240’ mit 10 Zeiteinheiten.
41
5.3. Beispiele zu Gruppierung und Aggregation
Wie hoch ist der Durchschnittspreis aller Produkte insgesamt pro Zeiteinheit?
Das Produkt ’Rennrad’ hat im Zeitraum [1, 7] den Preis 300; ’Mountainbike’ kostet in
diesem Zeitraum 270. Die Anfrage sollte also beispielsweise für den Zeitraum [1, 7] den
= 285 liefern.
Durchschnittspreis 300+270
2
ΓZeit
Zeit # Zeit, Durchschnitt = avg(Preis) (R)
Damit für jeden einzelnen Zeitpunkt der Durchschnittspreis bestimmt wird, muss hier
ΓZeit
... benutzt werden. Eine Formulierung mit dem klassischen Gruppierungsoperator Γ...
ergäbe πZeit, Preis (R) als Ergebnis, denn alle Zeit-Intervalle in R sind verschieden.
Wie hoch ist der Durchschnittspreis pro Produkt pro Jahr?
Angenommen die Zeiteinheiten im ’Zeit’-Attribut entsprechen fortlaufenden Monaten
vom Januar 2000 an, also z.B.: Das Produkt ’Mountainbike’ hat im Zeitraum vom
”
Januar 2000 (1) bis August 2001 (20=12+8) den Preis ’270’“. In diesem Fall läßt sich S
um ein Attribut ’Jahr’ erweitern, welches das zum Zeitstempel gehörige Jahr angibt:
(S)
X := εZeit
begin(Zeit)
e+1999
Jahr=d
12
Bemerkung: Die Benutzung des erweiterten Operators εZeit
ist notwendig, damit ein
...
Zeitstempel eindeutig einem Jahr zugeordnet werden kann. Im gepackten“ Zustand ist
”
dies hier nicht immer möglich (etwa bei [1, 20]).
Wieder sind zwei Formulierungen denkbar:
(Zeit)
ΓProdukt, Jahr # Produkt, Jahr, Durchschnitt = avg(Preis) (X)
270∗12
= 270 für das Jahr 2000
Für Mountainbikes ergibt die mit ΓZeit
... formulierte Anfrage
12
270∗8+240∗4
und
=
260
für
2001;
entsprechend
liefert
die
Anfrage
mit dem klassischem
8+4
270
270+240
Γ-Operator 1 = 270 für 2000 und
= 255 für 2001.
2
Wann ist der frühste Zeitpunkt des Beginns der Produktion pro Hersteller pro
Produkt?
Der gesuchte Zeitpunkt wäre z.B. ’8’ für den Hersteller ’Shnel’ und das Produkt ’Rennrad’.
ΓHersteller, Produkt # Hersteller, Produkt, Beginn = min(Beginn) (εBeginn=begin(Zeit) (R))
Durch die Verwendung des Intervalloperators begin wird der frühste Zeitpunkt eines
Zeitraums ermittelt.
42
5.3. Beispiele zu Gruppierung und Aggregation
Wie lange wird im Durchschnitt ein bestimmtes Produkt von einem Hersteller
produziert?
Rennräder werden etwa vom Hersteller ’Teua’ durchschnittlich
lang produziert.
7+5
2
= 6 Zeiteinheiten
ΓHersteller, Produkt # Hersteller, Produkt, Durchschnitt = avg(Anzahl) (εAnzahl=count(Zeit) (R))
Der Intervalloperator count liefert die Länge eines Zeitraums.
43
6. Optimierung
Die erweiterte Relationenalgebra basiert auf pack und unpack (siehe 3.4). Für eine Realisierung der erweiterten Relationenalgebra erscheint es deshalb sinnvoll, diese Operatoren
möglichst optimal zu implementieren.
Insbesondere unpack erscheint hier kritisch, denn unter Umständen enthält eine Relation im unpacked“-Zustand sehr viel mehr Tupel als das letztendliche Ergebnis. Wenn
”
möglich sollte also die Materialisierung von ungepackten“ Relationen vermieden werden.
”
Für diesen Abschnitt seien X = (S, I) und Y Relationen. L = l1 , . . . , ln sei eine Liste
von Attributnamen intervallwertiger Attribute von X oder Y , und L := def(S) − L sei
die Menge aller Attribute von X, die nicht in L vorkommen.
6.1. Zerlegung in Teilintervalle – split
Die komplette Zerlegung einer Relation X in Einheitsintervalle durch unpackL (X) ist
häufig unnötig: meist genügt es zu fordern, dass die betreffenden Intervalle nicht überlappen. Eine Zerlegung von X in maximale, nicht überlappende Intervalle hat den Vorteil,
dass für gewöhnlich weniger Tupel produziert werden als durch unpack(X). In den meisten Fällen kann unpack durch einen Operator split ersetzt werden, der solch eine
Zerlegung in Teilintervalle leistet:
splitlPX (X) zerlegt die Tupel einer Ausgangsrelation X für ein intervallwertiges Attribut l anhand einer Punktmenge PX . Ein Tupel mit dem l-Intervallwert [b, e] wird durch
einen Punkt p ∈ PX in zwei Teile“ mit [b, p − 1] und [p, e] gespalten, falls b < p ≤ e gilt.
”
Ein Tupel x ∈ X mit x(l) = [b, e] wird anhand von
b < p1 < · · · < pm ≤ e für p1 , . . . , pm ∈ PX
demnach durch eine Menge von Tupeln mit folgenden l-Werten ersetzt:
[b, p1 − 1], [p1 , p2 − 1], . . . , [pm−1 , pm − 1], [pm , e]
Algorithmus für splitlPX (X):
Für alle x ∈ X:
Setze q := begin(x(l)).
Für alle p ∈ PX in aufsteigender Reihenfolge mit begin(x(l)) < p und p ≤ end(x(l)):
Füge ein Tupel t mit gleichen Attributwerten wie x bis auf
t(l) := [q, p − 1] dem Ergebnis hinzu.
Setze q := p.
Füge ein Tupel t mit t(l) := [q, end(x(l))] dem Ergebnis hinzu.
44
6.1. Zerlegung in Teilintervalle – split
Analog zu unpackL (X) wird splitL (X) durch die Hintereinanderausführung für alle
Attribute in L = l1 , . . . , ln definiert:
l
splitLPX (X) := splitlPnX (splitPn−1
(. . . splitlP1X (X) . . . ))
X
Maximale nicht-überlappende Intervalle
Will man erreichen, dass die l-Intervalle zweier Tupel aus X nur überlappen, falls sie
gleich sind, soll also die Bedingung
∀x, x̃ ∈ X : x(l) overlaps x̃(l) ⇒ x(l) = x̃(l)
erfüllt sein, kann die Menge PX folgendermaßen gewählt werden:
PX := { begin(x(l)) : x ∈ X ∧ ∃ x̃ ∈ X ∧ x(l) 6= x̃(l) ∧ begin(x(l)) ∈ x̃(l) }
∪ { end(x(l)) + 1 : x ∈ X ∧ ∃ x̃ ∈ X ∧ x(l) 6= x̃(l) ∧ end(x(l)) ∈ x̃(l) }
PX entsteht durch alle Anfangs- und Endpunkten von l-Intervallen aus X, die im lIntervall eines anderern Tupels liegen (vgl. Abbildung 6.1 im unteren Beispiel).
PX ist die Menge mit der minimalen Anzahl von Elementen für die splitlPX (X) obige
Bedingung erfüllt1 . Folglich ist die Zerlegung der Tupel von X anhand von PX so grob
wie möglich, die Intervalle haben also größtmögliche Länge und sind damit in diesem
Sinn maximal.
Eine Zerlegung in maximale nicht-überlappende Intervalle ist auch mit einer einfacher
zu konstruierenden Punktmenge möglich – siehe 6.5.1.
Beispiel:
Name
VT
Müller
[2, 15]
Mit X :=
ist PX = {3, 13}
Müller [60, 68]
Schmidt [3, 12]
Name
VT
Müller
[2, 2]
Müller
[3, 12]
und damit splitVT
.
PX (X) =
Müller [13, 15]
Müller [60, 68]
Schmidt [3, 12]
1
Annahme: Es genügt eine Menge QX mit |QX | < |PX |. Für p ∈ PX − QX existieren x, x̃ ∈ X
mit x(l) 6= x̃(l) und es gilt p ∈ x(l) (bzw. p − 1 ∈ x(l)) sowie p ∈ x̃(l) (bzw. p − 1 ∈ x̃(l)) also
x(l) overlaps x̃(l).
45
6.2. Vermeidung von unpack und pack
Müller
Schmidt
3
12
Abbildung 6.1.: Graphische Veranschaulichung von splitVT
PX (X)
6.2. Vermeidung von unpack und pack
Für fast alle Operatoren der erweiterten Relationenalgebra ist eine Implementierung
möglich, die keine Materialisierung der Ausgangsrelationen im unpacked“-Zustand be”
nötigt. In manchen Fällen kann sogar eine äquivalente Formulierung ohne anfängliches
unpack angegeben werden. Das abschließende pack ist ebenfalls nicht immer nötig: Sind
die Ausgangsrelationen bereits gepackt“, so bleibt diese Eigenschaft bei einigen Opera”
toren erhalten. Im folgenden wird jeder Operator detailliert besprochen.
6.2.1. Projektion
Da für die Projektion die konkreten Werte eines Tupels unwichtig sind, spielt es keine
Rolle ob die Ausgangsrelation ungepackt“ vorliegt oder nicht:
”
L
πA (X) := packL ( πA (unpackL (X)) ) = packL ( πA (X) )
Werden alle Attribute von X projiziert (oder kein Attribut aus L) kann auch packL
entfallen.
6.2.2. Erweiterung
Bei der Erweiterung
εLb=β (X) := packL ( εb=β (unpackL (X)) )
einer Relation X um ein Attribut b wie sie in 3.1.2 beschrieben ist, sind in Abhängigkeit
von β zwei Fälle zu unterscheiden: Gilt β = β|L , wird also für die Berechnung von b
kein Gebrauch von den intervallwertigen Attributen aus L gemacht, dann ist unpackL
unnötig:
εLb=β (X) = packL ( εb=β (X) )
Das abschließende packL kann auch hier entfallen, sofern X bereits entsprechend ge”
packt“ ist.
Andernfalls läßt sich εLb=β (X) in einem einzigen Durchlauf über X erzeugen. In diesem
Fall müssen entsprechend auch nur intervallwertige Attribute betrachtet werden, die β
wirklich benötigt: Ist l ∈ L = {l1 , . . . , ln } so kann dieses l entfallen, falls β = β|def(S)−{l}
gilt.
46
6.2. Vermeidung von unpack und pack
Algorithmus:
Für alle x ∈ X:
Für alle pi ∈ x(li ) (1 ≤ i ≤ n):
Berechne für ein Tupel mit gleichen L-Werten wie x, aber mit Einheitsintervallen
[pi , pi ] das Ergebnis von β. Bilde also ein Tupel t mit t|L := x|L , t(li ) := [pi , pi ],
setze t(b) := β(t|def(S) ) und füge t dem Ergebnis hinzu.
Wende packL für die eben erzeugten Tupel an.
Durch das auf Tupelebene“ (Pipelining – siehe 6.3.1) für jedes x ∈ X durchgeführte
”
packL , wird die Materialisierung von unpackL (X) auf einzelne Tupel beschränkt. Liegt
jedoch X nicht bereits gepackt“ vor, so kann dadurch kein gepacktes“ Ergebnis garan”
”
tiert werden und es wird zusätzlich ein abschließendes packL (X) benötigt.
Ist mehr über β (und X) bekannt, ist es manchmal möglich εL durch ε zu ersetzen:
Die im Beispiel 5.3.2 verwendete Erweiterung um das Attribut ’Jahr’ könnte mit den
regulären Operator ausgedrückt werden, wenn kein Zeitstempel mehr als ein Jahr enthält.
6.2.3. Selektion
Anhand der Selektionsformel ϕ einer Selektion
σϕL (X) := packL ( σϕ (unpackL (X)) )
können analog zur Erweiterung zwei Fälle unterschieden werden: Gilt ϕ = ϕ|L , ist die
Selektion also von den intervallwertigen Attributen aus L unabhängig, dann ist unpackL
unnötig:
σϕL (X) := packL ( σϕ (X) )
Wieder entfällt packL falls X bereits entsprechend gepackt“ ist.
”
Andernfalls läßt sich auch σϕL (X) in einem einzigen Durchlauf über X ohne die Materialisierung von unpackL (X) erzeugen:
Für alle x ∈ X:
Für alle pi ∈ x(li ) (1 ≤ i ≤ n):
Berechne für ein Tupel mit gleichen L-Werten wie x, aber mit Einheitsintervallen
[pi , pi ] das Ergebnis von ϕ. Füge also das Tupel t mit t|L := x|L und t(li ) := [pi , pi ]
der Ergebnisrelation hinzu, falls ϕ(t) = wahr ist.
Wende packL für die eben erzeugten Tupel an.
Wie bei εLb=β (X) sind nur die intervallwertigen Attribute wichtig, die wirklich von ϕ
benötigt werden: Ist l ∈ L so kann dieses l entfallen, falls ϕ = ϕ|def(S)−{l} gilt. Ebenso
wird zusätzlich ein abschließendes packL (X) benötigt, sollte X nicht bereits gepackt“
”
vorliegen.
Angenommen ϕ läßt sich in einen von Attributen in L unabhängigen Teil ϕ1 und einen
abhängigen Teil ϕ2 zerlegen: ϕ = ϕ1 ∨ ϕ2 mit ϕ1 = ϕ1 |L und ϕ2 6= ϕ2 |L . Dann kann
bereits vor der inneren Schleife ( Für alle pi ∈ x(li )“) geprüft werden, ob ein Tupel x
”
selektiert wird, also ϕ1 (x) = wahr gilt. Ist dies der Fall, so ist es möglich den Test für
ϕ2 (x) zu übergehen, das Tupel in das Ergebnis zu übernehmen und mit dem nächsten
Tupel fortzufahren. (Analog wäre auch eine konjuktive Zerlegung ϕ = ϕ1 ∧ ϕ2 möglich.)
47
6.2. Vermeidung von unpack und pack
6.2.4. Verbund
Für den erweiterte Verbund
Xo
nL Y := packL ( unpackL (X) o
n unpackL (Y ) )
genügt die Zerlegung in maximale nicht-überlappende Intervalle:
Xo
nL Y = packL ( splitLPX∪Y (X) o
n splitLPX∪Y (Y ) )
Die für split benötigte Punktmenge PX∪Y ergibt sich hier aus den Intervallgrenzen der
beiden Relationen X und Y.
Beispiel:
Name
Meier
Müller
Sei X :=
Müller
Schmidt
Müller
VT
Name
VT
[6, 13]
Müller [10, 20]
[10, 15]
Müller [33, 44]
und Y :=
.
[18, 20]
Schmidt [22, 32]
[21, 55]
Schmidt [45, 50]
[56, 70]
Schulze [51, 55]
Dann können die VT-Intervalle anhand der Punktmenge
PX∪Y := {10, 14, 16, 18, 22, 33, 45, 51, 56} zerlegt werden:
Name
Meier
Meier
Müller
Müller
Müller
splitVT
PX∪Y (X) =
Schmidt
Schmidt
Schmidt
Schmidt
Schmidt
Müller
VT
[6, 9]
Name
VT
[10, 13]
Müller [10, 13]
[10, 13]
Müller [14, 15]
[14, 15]
Müller [16, 17]
[18, 20]
, splitVT
(Y
)
=
Müller
[18, 20]
PX∪Y
[21, 21]
Müller [33, 44]
[22, 32]
Schmidt [22, 32]
[33, 44]
Schmidt [45, 50]
[45, 50]
Schulze [51, 55]
[51, 55]
[56, 70]
Name
Müller
Müller
splitLPX∪Y (X) o
n splitLPX∪Y (Y ) ergibt
Müller
Schmidt
Schmidt
48
VT
[10, 13]
[14, 15]
[18, 20]
[22, 32]
[45, 50]
6.2. Vermeidung von unpack und pack
Für den Spezialfall, dass keine gleichnamigen, intervallwertigen Attribute von X und Y
in L enthalten sind, ist o
nL... schlicht unnötig:
Xo
nL Y = packL (X o
nY)
packL kann hier entfallen, wenn X und Y bereits gepackt“ sind.
”
Alternativ läßt sich der erweiterte Verbund auch direkt auf den klassischen Operator
abbilden: Mit dem Intervalloperator overlaps werden Verbundpartner bestimmt, dann
mit intersect das Schnittintervall berechnet.
Sei etwa l ∈ L das einzige gleichnamige, intervallwertige Attribut von X und Y . Dann
kann zunächst der klassische Verbund für alle anderen gleichnamigen Attribute gebildet
werden. Hierzu ist l etwa in xl (für X) bzw. yl (für Y ) umzubenennen2 :
R := ρ l=xl (X) o
n ρ l=yl (Y )
Mittels overlaps wird nun festgestellt ob Verbundpartner für das Attribut l vorliegen,
wobei intersect den zu l gehörigen Wert liefert:
S := ε l=xl intersect yl (σxl overlaps yl (R))
Zuletzt werden die jetzt überflüssigen Attribute xl und yl von S entfernt und die Ergebnisrelation gepackt“:
”
Xo
nl Y = packl (πAlle Attribute bis auf xl und yl (S))
Für mehrere gleichnamige, intervallwertige Attribut aus L kann analog vorgegangen
werden: Jedes Attribut ist wie oben zunächst exklusiv für X und Y umzubenennen.
Ebenso muss für jedes Intervallattribut die overlaps-Bedingung gelten und das zugehörige Intervall mit intersect berechnet werden. Abschließend ist für das entsprechend
projizierte Ergebnis packL anzuwenden.
Im Beispiel:
εVT = XVT intersect YVT (σXVT overlaps YVT (ρVT = XVT (X) o
n ρVT = YVT (Y )) =
Name
Müller
Müller
Schmidt
Schmidt
XVT
[10, 15]
[18, 20]
[21, 55]
[21, 55]
YVT
[10, 20]
[10, 20]
[22, 32]
[45, 50]
VT = XVT ∩ YVT
[10, 15]
[18, 20]
[22, 32]
[45, 50]
Anmerkungen:
• Nach dem letztgenannten Verfahren kann pack entfallen, wenn L nur ein einziges
Attribut enthält und X und Y bereits gepackt“ sind.
”
• Für den natürlichen Verbund von zwei gleichen Relationen ( Self Join“) gilt stets
”
Xo
nL X = X o
n X.
2
O.B.d.A gibt es noch kein Attribut xl in X bzw. yl in Y .
49
6.2. Vermeidung von unpack und pack
6.2.5. Vereinigung
Für die Vereinigung zweier Relationen gilt folgendes Distributivgesetz:
unpackL (X) ∪ unpackL (Y ) = unpackL (X ∪ Y )
Damit kann das anfängliche unpack kann entfallen.
X ∪L Y : = packL ( unpackL (X) ∪ unpackL (Y ) )
= packL (unpackL (X ∪ Y ))
= packL (X ∪ Y )
6.2.6. Differenz
Die Differenz
X −L Y := packL ( unpackL (X) − unpackL (Y ) )
kann wie der Verbund durch split ausgedrückt werden:
X −L Y := packL ( splitL PX∪Y (X) − splitL PX∪Y (X) )
Beispiel: Mit den Beispielrelationen X und Y aus 6.2.4 ergibt sich:
Name
Meier
Meier
L
L
split PX∪Y (X) − split PX∪Y (X) = Schmidt
Schmidt
Schmidt
Müller
VT
[6, 9]
[10, 13]
[21, 21]
[33, 44]
[51, 55]
[56, 70]
Differenz für genau ein Attribut
Enthält L genau ein Attribut l, dann läßt sich X −l Y berechnen ohne auf split zurückgreifen zu müssen. Ähnlich dem in 6.2.4 beschriebenen Verfahren läßt sich zunächst
ein Verbund von X und Y bilden:
R := ρ l=xl (X) n ρ l=yl (Y )
Ein Tupel des Minuenden X, das keinen Verbundpartner im Subtrahenden Y hat, muss
in der Ergebnisrelation vorkommen. Der obige Verbundoperator n ( Outer Join“) liefert
”
daher alle Tupel aus X ggfs. zusammen mit Verbundpartnern aus Y .
Der Operator n ist nicht Teil der in 3.1 definierten Relationenalgebra, weil hierfür ein
Wert für undefiniert“ eingeführt werden müsste (siehe folgendes Beispiel). (In Oracle ist
”
solch ein null-Wert jedoch vorhanden und n kann etwa Left Outer Join implementiert
werden.)
Zur Differenzbildung genügt es Tupel aus R zu betrachten für die XVT overlaps
YVT gilt oder für die YVT nicht definiert ist:
S := σxl ist undefiniert oder xl overlaps yl (R)
50
6.2. Vermeidung von unpack und pack
Im Beispiel:
σYVT ist undefiniert oder XVT overlaps YVT (ρVT = XVT (X) n ρVT = YVT (Y )) =
Name
Meier
Müller
Müller
Schmidt
Schmidt
XVT
[6, 13]
[10, 15]
[18, 20]
[21, 55]
[21, 55]
YVT
undefiniert
[10, 20]
[10, 20]
[22, 32]
[45, 50]
Die Differenz kann nun mit Hilfe einer neuen Aggregationsfunktion minus berechnet
werden:
X −l Y = packl (ΓL# Alle Attribute aus L, minus(xl,yl) (S))
Auf die so erzeugten Partitionen wirkt die Aggregationsfunktion minus, die die Differenz
zwischen xl-Wert und den entsprechenden yl-Werten bildet. Die so erzeugten Intervalle
werden zusammen mit den anderen zugehörigen Attributen (aus L) ausgegeben.
Algorithmus für minus: Der folgende Algorithmus für die Aggregationsfunktion minus
verlangt eine aufsteigende Sortierung nach begin(xl) und (zweitranging nach) begin(yl).
Für eine Gruppe G sind beginnend mit dem ersten Tupel folgende Schritte auszuführen:
Für ein Tupel g ∈ G:
1.
Setze b, e ∈ N auf den Wert des xl-Attributs: [b, e] := g(xl).
2.
Solange e + 1 ≥ begin(g(xl)) gilt und g(yl) definiert ist:
Setze e := end(g(xl)) falls e < end(g(xl)) ist.
Ist b < begin(g(yl)), dann füge ein Tupel x mit x|L := g|L und
x(l) := [b, begin(g(yl)) − 1] dem Ergebnis hinzu.
Setze b := end(g(yl)) + 1 falls b ≤ end(g(yl)) ist.
Fahre mit dem nächsten Tupel für g fort.
3.
Sofern b ≤ e gilt, füge dem Ergebnis ein Tupel x mit x|L := g|L
und x(l) := [b, e] hinzu.
Fahre mit dem nächsten Tupel für g fort.
Mit diesem Algorithmus wird kein abschließendes pack benötigt (vgl. den entsprechenden
Algorithmus für pack in 6.3.1).
Im Beispiel: Es ergibt sich folgender Ablauf des Algorithmus:
51
6.2. Vermeidung von unpack und pack
Schritt
1
3
1
2
3
1
2
3
1
2
2
3
Name
Meier
Meier
Müller
Müller
Müller
Müller
Müller
Müller
Schmidt
Schmidt
Schmidt
Schmidt
XVT
[6, 13]
[6, 13]
[10, 15]
[10, 15]
[10, 15]
[18, 20]
[18, 20]
[18, 20]
[21, 55]
[21, 55]
[21, 55]
[21, 55]
YVT
Ausgabe
undefiniert
–
undefiniert
(Meier, [6, 13])
[10, 20]
–
[10, 20]
–
[10, 20]
–
[10, 20]
–
[10, 20]
–
[10, 20]
–
[22, 32]
–
[22, 32]
(Schmidt, [21, 21])
[45, 50]
(Schmidt, [33, 44])
[45, 50]
(Schmidt, [51, 55])
[b, e]
[6, 13]
[6, 13]
[10, 15]
[21, 15]
[21, 15]
[18, 20]
[21, 20]
[21, 20]
[21, 55]
[33, 55]
[51, 55]
[45, 55]
6.2.7. Durchschnitt
Der Durchschnitt
X ∩L Y := packL ( unpackL (X) ∩ unpackL (Y ) )
muss nicht durch X −L (X −L Y ) implementiert werden. Für den Durchschnitt als Spezialfall des Verbunds gilt:
X ∩L Y = X o
nL Y
6.2.8. Gruppierung und Aggregation
Die Vermeidung von unpack Gruppierung und Aggregation
ΓLA # b1 =α1 ,...,bn =αn (X) := packL ( ΓA # b1 =α1 ,...,bn =αn (unpackL (X)) )
ist ohne genauere Kenntnis über die benutzten Aggregationsfunktionen nicht möglich.
Allgemein läßt sich die Materialisierung einer ungepackten“ Relation auf die durch die
”
Gruppierung erzeugten Gruppen beschränken: Wird etwa die Ausgangsrelation X in die
Gruppen G1 , G2 , . . . zerlegt, dann müssen stets nur jeweils unpackL (G1 ), unpackL (G2 ), . . .
materialisiert werden – nicht unbedingt unpackL (X). Allerdings ist durch diese Vorgehensweise nichts gewonnen wenn A = ∅ gilt, denn dann ist die ganze Relation X die
einzige Gruppe“.
”
Ist die Gruppierung von den Attributen in L unabhängig (gilt also A ∩ L = ∅) ist es
im Prinzip möglich ganz auf unpack zu verzichten, indem die Aggregationsfunktionen
ersetzt werden:
ΓLA # b1 =α1 ,...,bn =αn (X) = packL ( ΓA # b1 =α∗1 ,...,bn =α∗n (X) )
Eine Funktion αi wird hierbei durch eine Funktion αi∗ ersetzt, die das gleiche Ergebnis
wie αi liefert auch wenn die übergebene Gruppe G nicht ungepackt“ ist. Das sollte mög”
lich sein, denn aus G läßt sich (selbstverständlich) unpackL (G) konstruieren. Allgemein
52
6.2. Vermeidung von unpack und pack
wird so die Materialisierung von unpackL (G) lediglich vom relationalen Operator auf
die Aggregationsfunktion verschoben. Abhängig von der benutzten Funktion kann diese
Verschiebung allerdings Vorteile bringen.
Häufig benutzte Aggregationsfunktionen
Sei G eine Gruppe aus der erzeugten Gruppierung und o.B.d.A. L = l1 , . . . , ln mit n ∈ N,
dann können folgende Aggregationsfunktionen (vgl. 3.1.2) ersetzt werden:
• count kann durch count∗ ersetzt werden, indem Gebrauch vom Intervalloperator
count gemacht wird:
X Y
count∗ := {
count(t(li ))}
t∈G 1≤i≤n
• Ähnlich kann sum durch sum∗ ersetzt werden:
X
Y
sum∗ (a) := {
t(a) ·
count(t(li ))}
1≤i≤n
t∈G
• avg∗ analog mit sum∗ und count∗
• Da Minimum und Maximum vom gepackten“ oder ungepackten“ Zustand einer
”
”
Relation unabhängig sind, ist hier keine Ersetzung notwendig: min∗ (a) := min(a)
und max∗ (a) := max(a).
Diese Ersetzungen erlauben nun Gruppierung und Aggregation durchzuführen ohne dass
eine Materialisierung von unpack(G) nötig wäre.
Da Summe, Minimum und Maximum hier nicht für Intervalle definiert sind, kann
das oben angegebene Attribut a kein intervallwertiges Attribut sein. Wollte man etwa
eine Summe sum(τ (a)) über ein Intervallattribut a mittels einer Transformationsfunktion
τ : I −→ N bilden (z.B. τ (I) := begin(I) für ein Intervall I), so wäre zunächst über
εLneues Attribut=τ (X) ein neues Attribut für τ einzuführen, über das die Summe gebildet
werden kann (vgl. etwa die Beispiele in 5.3.2). In diesem Fall gilt beispielsweise für
sum:
ΓLA # b=sum(a) (X) = ΓA # b=sum∗ (b) (εLb=τ (X))
Gilt A∩L 6= ∅, ist also die Gruppierung von den Attributen in L abhängig, ist es unnötig
ganz X durch unpackL (X) bis hin zu Einheitsintervallen aufzuspalten. Eine Zerlegung in
maximale nicht-überlappende Teilintervalle mittels des split-Operators reicht aus. Die
Mengen PX sind hierfür entsprechend zu wählen (siehe 6.1). Dadurch wird es möglich
die Materialisierung einer ungepackten“ Gruppe wieder auf die Aggregationsfunktion
”
zu verschieben:
ΓLA # b1 =α1 ,...,bn =αn (X) = packL ( ΓA # b1 =α∗1 ,...,bn =α∗n (splitLPX (X)) )
53
6.3. Verbesserungen für pack
Beispiel: Die Frage nach dem Durchschnittspreises pro Zeiteinheit aus 5.3.2 führt zu
für P =
folgendem Ergebnis, welches die durchgeführte Zerlegung mittels splitZeit
P
{1, 8, 15, 21, 26} erkennen läßt:
Zeit
[1, 7]
[8, 14]
[15, 20]
[21, 25]
[26, 30]
Durchschnitt
285
260
270
255
240
6.3. Verbesserungen für pack
Nicht nur die Operatoren der erweiterten Relationenalgebra basieren auf unpack, sondern auch pack selbst (vgl. 3.3.3):
packL (X) := packln (packln−1 (. . . packl1 (unpackL (X)) . . . ) für L = l1 , . . . , ln
6.3.1. pack für genau ein Attribut
Enthält L nur genau ein Attribut, wird also pack für ein intervallwertiges Attribut l ∈ L
angewandt, ist nach Definition 3.3.2 kein unpack nötig. Ähnlich dem Algorithmus zur
Berechnung der erweiterten Differenz für ein Attribut in 6.2.6), läßt sich packl (X) in
einem Durchlauf berechnen: Hierfür sei X nach L gruppiert und jede dieser Gruppen nach
begin(l) aufsteigend sortiert. Für eine solche Gruppe G genügt es folgenden Algorithmus
auszuführen (beginnend mit dem ersten Tupel):
Für ein Tupel g ∈ G:
Setze b, e ∈ N auf den Wert des l-Attributs: [b, e] := g(l).
Solange e + 1 ≥ begin(g(l)) gilt:
Setze e := end(g(l)) falls e < end(g(l)) ist.
Fahre mit dem nächsten Tupel für g fort.
3.
Füge ein Tupel x mit x|L := g|L und x(l) := [b, e] dem Ergebnis hinzu.
Fahre mit dem nächsten Tupel für g fort.
1.
2.
Beispiel: Ist eine Relation X mit den zwei Attributen Name und VT gegeben:
Name
VT
Müller
[3,7]
Müller
[3,3]
X:= Müller
[8,8]
Müller [9,12]
Schmidt [1,1]
Schmidt [3,3]
54
6.3. Verbesserungen für pack
Dann wäre der Ablauf des beschriebenen Algorithmus für packVT folgender:
Schritt
1
2
2
2
3
1
3
1
3
Name
VT
Müller
[3, 7]
Müller
[3, 3]
Müller
[8, 8]
Müller [9, 12]
Müller [9, 12]
Schmidt [1, 1]
Schmidt [3, 3]
Schmidt [3, 3]
Schmidt [3, 3]
Ausgabe
[b, e]
–
[3, 7]
–
[3, 7]
–
[3, 8]
–
[3, 12]
(Müller, [3, 12]) [3, 12]
–
[1, 1]
(Schmidt, [1, 1]) [1, 1]
–
[3, 3]
(Schmidt, [3, 3]) [3, 3]
Pipelining
Das angegebene Verfahren für pack liefert das Ergebnis tupelweise zurück. Nachgeschaltete Operationen müssen also nicht auf die vollständige Materialisierung der Ergebnisrelation warten; umgekehrt benötigt pack keine vollständige Relation als Eingabe um
ein Ergebnistupel zu liefern (Pipelining). Beispielsweise wird so bei Erweiterung (6.2.2)
und Selektion (6.2.3) die Materialisierung von ungepackten Tupeln“ auf das gerade be”
trachtete beschränkt.
6.3.2. pack für mehr als ein Attribut
Enthält L mehr als ein intervallwertiges Attribut, dann ist packL (X) abhängig von der
Reihenfolge der Attribute in L (vgl. 3.3.3). Da unpackL (X) jedoch nicht von dieser
Reihenfolge abhängig ist und pack für ein einziges Attribut ohne unpack auskommt,
läßt sich zunächst ein unpack eliminieren:
packL (X) : = packln (packln−1 (. . . packl1 ( unpackL (X) ) . . . ))
= packln (packln−1 (. . . packl1 ( unpackl1 (unpackL−{l1 } (X)) ) . . . ))
= packln (packln−1 (. . . packl1 ( unpackL−{l1 } (X) ) . . . ))
Für das erste Attribut l1 aus L wird nun kein unpack mehr benötigt. Wie bereits bei
Differenz und Gruppierung und Aggregation kann das verbleibende unpackL−{l1 } durch
splitL−{l1 } ersetzt werden:
packln (packln−1 (. . . packl1 ( unpackL−{l1 } (X) ) . . . ))
L−{l1 }
= packln (packln−1 (. . . packl1 ( splitPX
(X) ) . . . ))
Nun wird die Ausgangsrelation X nur noch bis auf maximale nicht-überlappende Teilintervalle zerlegt, wenn die Punktmengen für splitL−{l1 } wie in 6.1 gewählt werden.
55
6.3. Verbesserungen für pack
Beispiel:
S#
[3, 5]
Für X = [2, 4]
[2, 4]
[2, 4]
P#
[1, 5]
[1, 4] (vgl. das Beispiel zu 3.3.3)
[5, 6]
[6, 9]
liefert die Anwendung von splitP#
PX anhand der Punktmenge PX = {1, 5, 6, 7}
S#
[3, 5]
[3, 5]
P#
splitPX (X) = [2, 4]
[2, 4]
[2, 4]
[2, 4]
P#
[1, 4]
[5, 5]
[1, 4] .
[5, 5]
[6, 6]
[7, 9]
S#
P#
[2, 5] [1, 4]
Ausgehend von diesem Ergebnis ist packS# (splitP#
(X))
=
[2, 5] [5, 5]
PX
[2, 4] [6, 6]
[2, 4] [7, 9]
S#
P#
und damit packP# (packS# (splitP#
(X)))
=
[2,
5]
[1,
5] = packS#, P# (X).
PX
[2, 4] [6, 9]
Umgekehrt ergibt splitS#
PX mit PX = {3, 4}
S#
[3, 4]
[5, 5]
[2, 2]
splitS#
(X)
=
[3, 4]
P
[2, 2]
[3, 4]
[2, 2]
[3, 4]
P#
[1, 5]
[1, 5]
[1, 4]
[1, 4] ,
[5, 6]
[5, 6]
[6, 9]
[6, 9]
S#
P#
[2, 2] [1, 9]
packP# (splitS#
PX (X)) =
[3, 4] [1, 9]
[5, 5] [1, 5]
P#, S#
und damit pack
S#
(X) = pack
P#
(pack
56
(splitS#
PX (X)))
S#
P#
= [2, 4] [1, 9] .
[5, 5] [1, 5]
6.4. Verbesserungen für unpack
6.4. Verbesserungen für unpack
Sollte eine Materialisierung von unpackL (X) explizit nötig sein, kann dies auf der Grundlage von packL (X) folgendermaßen geschehen:
Für alle x ∈ packL (X):
Für alle l ∈ L:
Für alle n ∈ x(l):
Füge ein Tupel t mit t|L := x|L und t(l) := [n, n] dem Ergebnis hinzu.
6.5. Verbesserungen für split
Die für den split-Operator benötigte Punktmenge kann einfacher berechnet werden als
in angegeben 6.1 ist.
Ein Pipelining auf Tupelebene wie für pack bzw. unpack ist zwar nicht möglich, trotzdem läßt sich durch Partitionierung der Ausgangsrelation der Umfang einer Materialisierung von Zwischenergebnissen vermindern.
6.5.1. Berechnung der Punktmenge
In 6.1 wurde die Menge PX eingeführt mit der durch splitlPX (X) eine Relation X in
maximale nicht-überlappende l-Intervalle zerlegt werden kann:
PX := { begin(x(l)) : x ∈ X ∧ ∃ x̃ ∈ X ∧ x(l) 6= x̃(l) ∧ begin(x(l)) ∈ x̃(l) }
∪ { end(x(l)) + 1 : x ∈ X ∧ ∃ x̃ ∈ X ∧ x(l) 6= x̃(l) ∧ end(x(l)) ∈ x̃(l) }
Dies ist jedoch auch mit einer einfacher zu berechnenden Punktmenge möglich:
[
{ begin(x(l)), end(x(l)) + 1 }
P̃X :=
x∈X
P̃X ⊃ PX ist eine Obermenge von PX , hat also eventuell nicht mehr die minimalen Anzahl
von Elementen. Allerdings erzeugt splitlP̃ (X) immer noch Intervalle größtmöglicher
X
Länge3 .
Liegt P̃X aufsteigend sortiert vor:
P̃ = {p1 , . . . , pm } mit pi < pi+1 für alle 1 ≤ i < m,
dann wird durch splitlP̃ (X) ein Tupel x ∈ X durch Tupel xi ersetzt, die sich nur im
X
Attribut l von x unterscheiden: xi (l) = [pi , pi+1 − 1] sofern x(l) overlaps xi (l) gilt.
3
Ist p̃ ∈ P̃X − PX dann existiert kein x ∈ X mit begin(x(l)) < p̃ ≤ end(x(l)). p̃ spaltet also kein
”
Tupel aus X“.
57
6.5. Verbesserungen für split
Anders formuliert läßt sich splitlP̃ (X) mit einer Relation QX die ein einziges Attribut
X
l und die Tupel xi (l) = [pi , pi+1 − 1] enthält, durch einen Verbund darstellen (vgl. 6.2.4):
n ρ l=ql (QX ))
splitlP̃X (X) = σxl overlaps yl (ρ l=xl (X) o
Die Berechnung von P̃X benötigt einen Durchlauf über alle l-Intervalle von X. Um diesen
Aufwand zu sparen, wäre es denkbar P̃X in gewisser Form für jede Relation vorzuhalten
– etwa in Gestalt der Relation QX . Sinnvoll wäre auch die Indexierung der Tupel einer
Relation X anhand der Punkte aus PX .
6.5.2. Pipelining und Partitionierung
Häufig ist es sinnvoll splitL (X) nur für einzelne Partitionen zu materialisieren und X
so Stück für Stück“ zu bearbeiten. Dieses Pipelining auf Basis einer Partitionierung
”
kann somit bei Differenz, pack und Gruppierung & Aggregation angewandt werden: Bei
X −L Y und pack für mehrere Attribute ist eine Partitionierung nach L möglich, bei
ΓLA#... (X) (siehe 6.2.8) eine Partitionierung nach L ∩ A.
Außerdem werden die Tupel von X eventuell feiner zerlegt als nötig wäre, wenn die
Menge der zerlegenden Punkte für ganz X gebildet wird. Werden sie für jede Partition
einzeln berechnet, können insgesamt weniger Tupel entstehen. Allerdings ist abzuwägen
ob die zusätzliche Erzeugung von Punktmengen den Mehraufwand lohnt.
Beispiel für X −L Y : Sind X und Y wie im Beispiel zur Differenz in 6.2.4, dann gibt
es verschiedene Werte für das Attribut ’Name’ etwa ’Müller’ und ’Schmidt’. Daher sind
für X die Partitionen
Name
VT
Name
VT
Müller [10, 15]
X1 =
und X2 =
zu betrachten, sowie
Müller [18, 20]
Schmidt [21, 55]
Müller [56, 70]
Name
VT
Name
VT
für Y die Partitionen Y1 = Müller [10, 20] und Y2 = Schmidt [22, 32] .
Müller [33, 44]
Schmidt [45, 50]
Bei ’Müller’ ist PX1 ∪Y1 = {10, 16, 18}, was keine Veränderung für X1 bedeutet und für
Y1 die Zerlegungen folgende Zerlegung liefert:
Name
Müller
VT
splitPX ∪Y (Y1 ) = Müller
1
1
Müller
Müller
VT
[10, 15]
[16, 17]
[18, 20]
[33, 44]
Für Y2 bedeutet die Zerlegung durch PX2 ∪Y2 = {22, 33, 45, 51} keine Veränderung. Für
X2 gilt:
58
6.5. Verbesserungen für split
Id
Schmidt
Schmidt
splitVT
PX2 ∪Y2 (X2 ) =
Schmidt
Schmidt
Schmidt
VT
[21, 21]
[22, 32]
[33, 44]
[45, 50]
[51, 56]
Wie angedeutet ist hier zu beobachten, dass durch die partitionsbasierte Zerlegung insgesamt weniger Tupel entstehen: 3 + 5 + 4 + 2 = 14 Tupel von X1 , X2 , Y1 und Y2 im
Gegensatz zu 9 + 7 = 16 Tupeln von X und Y im Beispiel von 6.2.4 (’Schulze’ und
’Meier’ nicht mitgezählt).
Pipelining für X −L Y
Ein Pipelining für X −L Y kann etwa durch folgenden Algorithmus geschehen:
Partitioniere X in X1 , X2 , . . . und Y entsprechend in Y1 , Y2 , . . . nach L.
Für jedes Xi :
Erzeuge für jedes l ∈ L die Punktmenge PXi ∪Yi über Xi und Yi .
Wende damit splitlPX ∪Y auf Xi und Yi an.
i
i
Füge packL (Xi − Yi ) dem Ergebnis hinzu.
Das abschließende pack kann entfallen, falls L genau ein Attribut enthält und der Minuend X in gepackter“ Form vorliegt. Für mehrere Attribute kann pack für jedes Attribut
”
einzeln erfolgen (siehe 6.3.1).
Zusätzliche Partitionierung nach L
Wie schon bei unpackL (X) ist bei splitL (X) die Reihenfolge in der split für die
einzelnen Attribute in L ausgeführt wird unwichtig. Ist allerdings splitl (X) bereits für
ein l ∈ L ausgeführt worden, kann in den hier beschriebenen Fällen X zusätzlich nach
diesem l partitioniert werden. Hierdurch entstehen bei der Anwendung von split für
das nächste Attribut aus L wieder weniger Tupel. Das so erzeugte Ergebnis ist allerdings
abhängig von der Reihenfolge der Liste L.
Beispiel für X −S#, P# Y :
S#
Sei X :=
[1, 70]
P#
und Y :=
[4, 16]
S#
[2, 15]
[60, 68]
P#
[4, 9] .
[5, 19]
0
Mit PX∪Y = {2, 16, 60, 69} ergibt splitS#
PX∪Y (Y ) = Y =: Y und
59
6.5. Verbesserungen für split
S#
[1, 1]
[2, 15]
splitS#
PX∪Y (X) =
[16, 59]
[60, 68]
[69, 70]
P#
[4, 16]
[4, 16]
=: X 0 .
[4, 16]
[4, 16]
[4, 16]
Für S#=[2, 15] ergibt sich die Punktmenge {4, 10} und für S#=[60, 68] die Menge
{5, 17}. Für alle anderen Werte von S# ist die Punktmenge gemäß 6.1 leer. Nach der
Anwendung von splitP# auf die S#-Partitionen ergibt sich:
S#
[1, 1]
[2, 15]
[2, 15]
X=
[16, 59]
[60, 68]
[60, 68]
[69, 70]
P#
[4, 16]
S#
[4, 9]
[10, 16]
[2, 15]
und Y =
[4, 16]
[60, 68]
[4, 4]
[60, 68]
[5, 16]
[4, 16]
P#
[4, 9]
.
[5, 16]
[17, 19]
0
Ohne zusätzliche Partitionierung nach S# enthielte splitP#
PX∪Y (X ) mit der Punktmenge
PX∪Y = {4, 5, 10, 17} 20 Tupel (statt 7): [4, 16] zerlegt in 4 Intervalle pro 5 Tupel.
0
splitP#
PX∪Y (Y ) enthielte 5 Tupel (statt 3).
60
7. Realisierung
In diesem Kapitel wird eine exemplarische Realisierung der erweiterten Relationenalgebra beschrieben. Es soll eine Anfragesprache an eine temporale Datenbank mit einem
einzigen Zeitstempel implementiert werden. Grundlage hierfür bildet das RDBMS Oracle
in Version 9.2 ([OTN], [OraDoc]).
Da eine vollständige Realisierung der erweiterten Relationenalgebra innerhalb des
DBMS aus den im folgenden genannten Gründen nicht möglich ist, besteht dieses Kapitel aus drei Teilen: Zunächst wird in 7.1 erläutert welche Erweiterungen im DBMS
vorgenommen werden. In 7.2 wird die Uebersetzung von Termen der erweiterten Algebra für das DBMS beschrieben. Abschließend wird in 7.3 eine Implementierung der
Relationenalgebra als Anfragesprache vorgestellt.
7.1. Erweiterung des DBMS
In Oracle ist keine relationale Algebra an sich vorhanden. Stattdessen können in der
Structured Query Language (SQL) Anfragen an Tabellen gestellt werden ([OraSQL]).
Zusätzlich ist es möglich in einer prozeduralen Sprache (Procedural Language/SQL –
PL/SQL) Prozeduren und Funktionen für SQL-Objekte zu implementieren ([OraPLSQL]).
Die Erweiterung der SQL-Syntax im Sinne der erweiterten Relationenalgebra ist in
Oracle nicht möglich. Daher findet die Auswertung eines Terms der Algebra außerhalb
des DBMS statt (siehe 7.3).
Eine Zuordung von relationalen Operatoren zu SQL-Konstrukten ist jedoch wie folgt
durchführbar: Sei X eine Relation mit den Attributen x1 , x2 , . . . und X die entprechende
SQL-Tabelle mit den Spalten x1, x2,.... Ebenso sei Y die entsprechende Tabelle zur
Relation Y .
relationaler Operator:
[Identität von] X
πx1 ,x2 (X)
εb=β (X)
ρb=x1
σϕ (X)
Xo
nY
X −Y
X ∪Y
X ∩Y
Γx1 ,x2 # b=α (X)
SQL-Konstrukt:
select * from X
SELECT x1, x2 from X
SELECT β as b, x1, x2,... from X
SELECT x1 as b, x2, x3,... from X
select * from X WHERE ϕ
select * from X NATURAL JOIN Y
select * from X MINUS Y
select * from X UNION Y
select * from X INTERSECT Y
select α as b from X GROUP BY x1, x2
61
7.1. Erweiterung des DBMS
SQL unterscheidet sich jedoch von den in 3.1 beschriebenen Ausgangsstrukturen:
• Eine Relation enthält ein Tupel nur höchstens einmal; in einer SQL-Tabelle kann
im Gegensatz dazu eine Zeile mehrfach vorkommen. Um dies auszugleichen kann
zu jeder erzeugten SQL-Anfrage explizit eine Duplikatelimination verlangt werden
(select DISTINCT).
• In SQL existiert ein expliziter Wert für undefiniert“: null. Dieser Wert erfährt
”
durch die erweiterte Relationenalgebra keine spezielle Behandlung – insbesondere
ist der null-Wert als Zeitstempel unzulässig.
Im folgenden wird davon ausgegangen, dass die bei Operatoren der erweiterten
Relationenalgebra verwendete Zeitstempel-Spalte keine null-Werte enthält. Für
sonstige Spalten (auch intervallwertige!) wird der null-Wert jedoch geduldet.
• Es gibt keinen Datentyp für Wahrheitswerte (etwa boolean) in SQL. Wahr“ wird
”
also entsprechend durch die Zahl 1 und falsch“ durch 0 dargestellt – etwa where
”
”
I_overlaps(Zeit1, Zeit2) = 1“ statt where I_overlaps(Zeit1, Zeit2)“.
”
7.1.1. Intervalle und Intervalloperatoren
Um Anfragen in der erweiterten Relationenalgebra nach SQL zu übersetzen, muss ein
Intervallbegriff zur Modellierung von Zeitstempeln im DBMS vorhanden sein.
Im Oracle RDBMS existieren bereits Datentypen für Intervalle (interval year to
month und interval day to second) und sogar ein Zeitstempel (timestamp).
Der Zeitstempel entspricht einer bis auf Sekundenbruchteile genauen Datumsangabe,
also eher einem wie in Kapitel 2 beschriebenen Zeitpunkt mit festgelegter Semantik. Entsprechend modellieren interval year to month und interval day to second Zeitspannen einer bestimmten Granularität. Solch eine Zeitspanne hat keinen Anfangszeitpunkt.
Implementierung eines Datentyps für Intervalle
Als Grundlage für die hier beschriebene Erweiterung erscheinen diese Datentypen ungeeignet. Deshalb wird ein neuer Datentyp für Intervalle erzeugt, wobei natürliche Zahlen
die zugrundeliegenden Zeitpunkte darstellen:
create or replace type interval_type as object (
b integer, -- Anfangszeitpunkt
e integer, -- Endzeitpunkt
-static function min return integer, -- kleinstmögliches b
static function max return integer, -- größtmögliches e+1
-constructor function interval_type (b integer, e integer)
return self as result,
62
7.1. Erweiterung des DBMS
-map member function convert return integer
);
Die map-Funktion dient
vall auf die ganze Zahl
gilt ein Intervall I nun
I.e < J.e gilt.
dem DBMS zum Vergleich von Intervallen: Sie bildet ein Interb * (max - min) + e ab. Durch den Vergleich dieser Zahlen
kleiner“ als ein Intervall J falls I.b < J.b oder zumindest
”
Nun wäre es natürlich möglich Schnittstellen zwischen interval-type und den bereits
vorhandenen Typen herzustellen: Zum Beispiel könnte ein Operator I_begin_as_date
zu einem interval-type-Intervall die zugehörige timestamp-Datumsangabe des Anfangszeitpunktes b liefern.
Implementierung der Intervalloperatoren
Ausgehend vom Datentyp interval-type lassen sich gemäß 3.2 Operatoren für Intervalle in PL/SQL implementieren. Jedem Operatornamen wird hierbei ein ’I_’ vorangestellt
um Konflikte mit SQL- oder PL/SQL-Schlüsselwörtern zu vermeiden. Wie schon angedeutet liefern Vergleichsoperatoren 0 für falsch“ und 1 für wahr“ zurück.
”
”
Beispiele:
create or replace function I_count (i interval_type)
return integer is
begin
return i.e - i.b +1;
end I_count;
create or replace function I_overlaps (i1 interval_type, i2 interval_type)
return integer is
begin
if (i1.b <= i2.e) and (i2.b <= i1.e) then
return 1;
end if;
return 0;
end I_overlaps;
create or replace function I_intersect (i1 interval_type, i2 interval_type)
return interval_type is
b
integer := i1.b;
e
integer := i1.e;
begin
if I_overlaps(i1, i2) = 1 then
if i2.b > b then b := i2.b; end if;
63
7.1. Erweiterung des DBMS
if i2.e < e then e := i2.e; end if;
return interval_type(b,e);
end if;
raise_application_error(-20979, ’illegal interval-intersection: ’
||I_toString(i1)||’ intersect ’||I_toString(i2));
end I_intersect;
Alle implementierten Intervalloperatoren sind in Anhang A aufgelistet.
7.1.2. Implementierung von count∗ , sum∗ und avg∗
Die in 6.2.8 beschriebenen erweiterten Aggregationsfunktionen count∗ , sum∗ und avg∗
könnten als gewöhnliche Aggregationsfunktionen mit zusätzlichem Zeitstempelargument
implementiert werden. Ist R die Tabelle aus 5.3.1, so könnte
select Produkt, avg(Preis, Zeit) from R group by Produkt
den nach der Zeit gewichteten Durchschnittspreis pro Produkt liefern. Da jeder Aggregationsfunktion in Oracle jedoch nur genau ein Argument erlaubt ist, müssen solche
Anfragen entsprechend mit dem Intervalloperator I_count umformuliert werden. Im
Beispiel für avg∗ :
select Produkt, sum(Preis * I_count(Zeit)) / sum(I_count(Zeit))
from R group by Produkt
Die Gewichtung nach einer Intervallspalte i muss also vom Benutzer selbst vorgenommen
werden: count∗ wird so zu sum( I_count(i) ), sum∗ (a) zu sum(a * I_count(i)) und
avg∗ (a) zu sum(a * I_count(i)) / sum(I_count(Zeit)).
7.1.3. Implementierung von pack
Um pack zu implementieren sind verschiedene Ansätze denkbar. Zwei Möglichkeiten
werden im folgenden näher erläutert, wobei das letztgenannte Verfahren bei der Implementierung zur Anwendung kommt.
Mengenwertige Aggregationsfunktionen
Da bei der Definition der erweiterten Relationenalgebra in Kapitel 3 Aggregationsfunktionen die Mengen zurückliefern eine wichtige Rolle spielen, ist es naheliegend zu Versuchen pack auch so zu implementieren. Zum Beispiel ist packZeit (R) für die Relation R
aus 5.3.1, definiert als (vgl. 3.3):
packZeit (R) := ΓProdukt, Preis # Produkt, Preis, Zeit=collapse(Zeit)
Mit einer entsprechend implementierten Aggregationsfunktion ließe sich die Anfrage
Zeit
πProdukt,
Zeit (R) wie folgt in SQL umsetzen:
64
7.1. Erweiterung des DBMS
select Produkt, pack(Zeit) from R group by Produkt, Preis
Hierbei wurde außer Acht gelassen, dass die von pack gelieferte Menge auch in der
Ergebnisrelation entsprechend entschachtelt“ werden muss. Dies läßt sich jedoch mit
”
vom DBMS bereitgestellten Mechanismen durchführen.
Dieses Konzept scheitert an der unvollkommenen Unterstützung von Mengen als Rückgabewert von selbstdefinierten Aggregationsfunktionen. Enthält die Rückgabemenge mehr
als etwa 50 Intervalle, so wird die Ausführung der Aggregationsfunktion mit einem internen Speicherfehler seitens Oracle abgebrochen. Es scheint, dass die internen Puffer
für umfangreichere Ergebnisse von Aggregationsfunktion zu klein dimensioniert sind.
Eine Variante von Aggregationsfunktionen in Oracle sind die Windowing Aggregate
”
Functions“ (siehe [OraDW]). Eine solche Funktion aggregiert für jedes Tupel der Gruppe
einen Wert bezüglich einer Umgebung ( Fenster“) dieses Tupels. Somit wäre es also
”
möglich – ohne eine Menge als Rückgabewert – mehr als einen einzigen Wert pro Gruppe
zurückzuliefern.
pack läßt sich allerdings nicht so implementieren, da nicht festgestellt werden kann,
ob noch Tupel aus der Gruppe folgen (was aber nötig ist – vgl. Algorithmus in 6.3.1).
(Es war möglich dieses Problem durch zweimalige Ausführung der Windowing Aggregate Function zu umgehen. Dieser Ansatz wurde jedoch nicht weiter verfolgt, weil eine
Implementierung mittels Pipelined Table Functions als vielversprechender erschien.)
Pipelined Table Functions
Das Oracle-DBMS bietet mit einer sogenannten Table Function die Möglichkeit eine
PL/SQL-Funktion zu implementieren, die eine Tabelle zurückliefert (siehe [OraDCD]).
Da in PL/SQL kein Datentyp für SQL-Tabellen existiert, muss allerdings der Rückgabewert einer solchen Table Function explizit umgewandelt werden (mit Hilfe des TABLEOperators). Als Eingabe benötigt eine Table Function für pack ebenfalls eine SQLTabelle. Hierzu wird eine Anfrage in einem CURSOR-Objekt gekapselt.
Zeit
Beispiel: Sei R die Tabelle aus 5.3.1. Dann läßt sich πProdukt,
Zeit (R) wie folgt übersetzen:
select * from TABLE( pack( CURSOR(
select Produkt, Zeit from R order by Zeit ) ) )
Zunächst sind die verwendeten Datentypen festzulegen:
create or replace package PACK_pkg as
type rowrec is record (
-- Datentyp einer Zeile
produkt varchar2(20),
zeit
interval_type
);
type rowrec_table is table of rowrec;
-- Datentyp der Rückgabe
type refcur is ref cursor return rowrec; -- Datentyp der Eingabe
end PACK_pkg;
65
7.1. Erweiterung des DBMS
Nun kann pack entsprechend dem Algorithmus aus 6.3.1 implementiert werden:
function pack (relation PACK_pkg.refcur) return PACK_pkg.rowrec_table
pipelined is
tupel
PACK_pkg.rowtype;
packed
PACK_pkg.rowtype;
new_group
boolean;
begin
fetch relation into tupel;
if relation%found then
packed := tupel;
loop
fetch relation into tupel;
exit when relation%notfound;
new_group := case
when not packed.produkt = tupel.produkt then true
when packed.zeit.e +1 < tupel.zeit.b then true
else false
end;
if new_group then
pipe row (packed);
packed := tupel;
else
if packed.zeit.e < tupel.zeit.e then
packed.zeit.e := tupel.zeit.e;
end if;
end if;
end loop;
pipe row (packed);
end if;
close relation;
return;
end pack;
Durch das Pipelining für nachfolgende Operatoren kann die Materialisierung der gesamten Ergebnistabelle vermieden werden (pipe row (packed)). Pipelining für vorangehende Operatoren (fetch relation into tupel) erlaubt den Umfang von Zwischenergebnissen zu minimieren (etwa bei unpack; siehe unten).
Der pack-Operator wird jedoch nicht nur für eine konkrete Relation benötigt, sondern
für Relationen allgemein. Das Schema solcher Relationen ist auch nicht im Voraus bekannt, weshalb die verwendeten Datentypen nicht wie im oben gezeigten Code ange-
66
7.1. Erweiterung des DBMS
geben werden können. Die Implementierung eines allgemeinen pack-Operators benötigt
also Datentypen, deren konkrete Struktur erst zur Laufzeit festgelegt werden muss.
Oracle bietet solche Typen an: Der Datentyp SYS_refcursor kapselt beliebige Anfragen ( Weakly Typed Cursor“) und mit dem Datentyp SYS.AnyDataSet lassen sich
”
beliebige Mengen modellieren (vgl. Transient and Generic Types“ in [OraDCD]). Eine
”
allgemeine Implementierung der pack-Funktion könnte also etwa diese Form haben:
function pack (relation SYS_refcursor) return table of SYS.AnyDataSet
pipelined is
tupel
SYS.AnyDataSet;
packed
SYS.AnyDataSet;
new_group
boolean;
begin
fetch relation into tupel;
[...]
end pack;
Leider scheint es nicht möglich, die Struktur der Tupel die einem SYS_refcursor entstammen, zur Laufzeit zu bestimmen. Das ist jedoch nötig um den pack-Algorithmus
durchzuführen: Im obigen Code wird durch fetch relation into tupel versucht ein
konkretes Tupel aus relation der Variablen tupel zuzuweisen. Dies schlägt zur Laufzeit
fehl, da tupel nicht den richtigen konkreten Typ hat.
Um trotzdem beliebige Relationen packen“ zu können, muss also vor einer SQL-Anfrage
”
die passende konkrete PL/SQL-Funktion für pack erzeugt werden (ggfs. auch mehrere Funktionen). Das bedeutet, dass in jedem Schritt bei der Auswertung eines Terms
der erweiterten Relationenalgebra alle Attribute inklusive deren Datentypen bekannt
sein müssen. Ist dies der Fall, kann anhand dieser Information eine konkrete packImplementierung erzeugt werden: Der Code für pack liegt nicht konkret vor, sondern
nur als Schablone (Template, Makro,. . . ). In diese wird der konkrete Text zu Attributnamen und Datentypen einer Relation eingesetzt. Der komplette konkrete Code wird
dann vor der eigentlichen Anfrage an das DBMS übergeben.
Beispiel: Aus
new_group := case $case_clause
when packed.$pack_arg.e +1 < tupel.$pack_arg.b then true
else false
end;
Zeit
wird im konkreten Fall für πProdukt,
Zeit (R) (vgl. oben):
new_group := case
when not packed.produkt = tupel.produkt then true
when packed.zeit.e +1 < tupel.zeit.b then true
else false
end;
67
7.1. Erweiterung des DBMS
Da die Auswertung der erweiterten Relationenalgebra im Evaluator-Teil der Implementierung (7.3) geschieht, findet dort auch die beschriebene Textersetzung statt.
7.1.4. Implementierung von unpack
Eine Realisierung von unpack wird für Selektion und Erweiterung benötigt (siehe 6.2.3
und 6.2.2). unpack kann analog zu pack als Table Function nach dem Algorithmus aus
6.4 implementiert werden. Dies ermöglicht ein Pipelining wie in 7.1.3 beschrieben.
Da der Algorithmus für pack (und unpack) eine sortierte (bzw. partitionierte) Eingabe
erfordert (6.3.1), muss entweder unpack diese Sortierung liefern, oder das (gesamte!)
Ergebnis von unpack erneut sortiert werden. Für die Selektion σϕZeitstempel ist ersteres
möglich, weil lediglich Tupel bezüglich ϕ herausgefiltert werden.
Bei der Erweiterung εZeitstempel
ist das für allgemeines β nicht möglich, denn die Reib=β
henfolge der Werte für b ist nicht bekannt. Um zusätzlich nach b zu sortieren kann es
also notwendig sein, das gesamte ungepackte“ Ergebnis zu materialisieren! Denkbar wä”
re pack, die Erweiterung und unpack als eine einzige Table Function zu implementieren
um den Algorithmus aus 6.2.2 zu realisieren, wobei ggfs. β genauer festgelegt werden
müsste. Dieser Ansatz wurde hier allerdings aus Zeitgründen nicht implementiert.
7.1.5. Implementierung von split
Für split muss zunächst die Menge der zerlegenden Punkte gebildet werden. Ist R
eine Tabelle entsprechend der Beispielrelation aus 5.3.1, dann kann dies folgendermaßen
geschehen:
select rownum as n, p from
(select alias.Zeit.b as p from R alias
UNION
select alias.Zeit.e+1 as p from R alias)
order by p asc;
Die Zeilen der Ergebnistabelle entsprechen den p1 , . . . , pm aus 6.5.1, wobei die Spalte
n den Index repräsentiert. (Ohne alias für R erkennt Oracle die Spalte Zeit nicht als
intervallwertige Spalte.)
Die Tabelle Q gemäß 6.5.1 wird entsprechend gebildet:
select interval_type(B.p, E.p-1) as Zeit from
(select rownum as n, p from
(select alias.Zeit.b as p from R alias
UNION
select alias.Zeit.e+1 as p from R alias)
order by p asc) B,
(select rownum as n, p from
(select alias.Zeit.b as p from R alias
UNION
68
7.2. Übersetzung von Termen
select alias.Zeit.e+1 as p from R alias)
order by p asc) E
where E.n = B.n+1;
Schließlich ergibt sich split(R) aus einem Verbund mit Q:
select Produkt, Preis, I_intersect(R.Zeit, Q.Zeit) as Zeit
from R, Q
where I_overlaps(R.Zeit, Q.Zeit) = 1;
Die Verwendung einer Pipelined Table Function für split erscheint unsinnig, da für die
Bildung der Punktmenge bzw. von Q die gesamte Ausgangsrelation zunächst komplett
durchlaufen werden muss. Deshalb wird R explizit materialisiert, d.h. als SQL-Tabelle
erzeugt (create table ... as (select ...)). Genauso wird split(R) gebildet und
ebenfalls explizit materialisiert.
Um eine allgemeine Form des split-Operators zu erhalten, wird analog zu pack eine Textersetzung für alle von der konkreten Relation abhängigen Teile des Verfahrens
durchgeführt.
Bemerkung: Eine Implementierung von split anhand beliebiger Punktmengen wäre
nach diesem Verfahren zwar auch möglich, wird aber im weiteren nicht benötigt. Der
einzige Fall bei dem split überhaupt benötigt wird, ist die Gruppierung nach dem
Zeitstempel.
7.1.6. Temporale Metadaten
Für die Auswertung von Termen der erweiterten Relationenalgebra müssen die Namen und Datentypen aller Attribute von jeder Relation in der Datenbank bekannt
sein (vgl. 7.1.3). Im Oracle-DBMS ist diese Information in Form einer Metadatentabelle
(USER_TAB_COLUMNS; siehe [OraDD]) vorhanden.
Zusätzlich ist es sinnvoll zu wissen ob eine Relation gepackt“ vorliegt. Für manche
”
Operatoren der erweiterten Relationenalgebra kann dann das abschließende pack entfallen (siehe Kapitel 6). Diese wird in einer entsprechenden Metadatentabelle namens
USER_TEMPORAL_TABLES festgehalten:
create table USER_TEMPORAL_TABLES (
table_name varchar2(30) not null,
packed_on varchar2(30) not null
)
7.2. Übersetzung von Termen
Die Operatoren der erweiterten Relationenalgebra können auf Basis von pack, split
und anderen Table Functions in eine einzige SQL-Anfrage übersetzt werden. Wie in 7.1
69
7.2. Übersetzung von Termen
beschrieben, müssen hierfür ggfs. vorher PL/SQL-Funktionen erzeugt und Relationen
explizit materialisiert werden. Für jeden erweiterten Operator wird im folgenden das
zugehörige Übersetzungsmuster angegeben.
Es sei (o.B.d.A) X eine Relation mit den Attributen z, x1 und x2 und X die entprechende SQL-Tabelle mit den Spalten z, x1 und x2. Zu einer Relation Y sei Y die
entsprechende SQL-Tabelle. z (bzw. z) sei der gemeinsame Zeitstempel von X und Y .
7.2.1. Projektion
Wie schon im Beispiel für pack (7.1.3) angedeutet, läßt sich etwa πxz 1 ,x2 ,z (X) folgendermaßen implementieren:
select * from TABLE( pack( CURSOR(
SELECT x1, x2, z from X order by x1, x2, z )))
Das abschließende pack kann entfallen, wenn kein Zeitstempel nach der Projektion mehr
übrig ist, etwa bei πxz 1 ,x2 (X):
SELECT x1, x2 from X
7.2.2. Erweiterung
Für die Erweiterung εzb=β (X) wird wie in 6.2.2 beschrieben unpack benötigt. unpack
kann analog zu pack als Pipelined Table Funktion implementiert werden (siehe 7.1.4).
Die entsprechende Anfrage lautet:
select * from TABLE( pack( CURSOR
SELECT β as b, x1, x2 from TABLE( unpack( CURSOR (
select * from X order by x1, x2, z )))
order by x1, x2, b, z )))
7.2.3. Selektion
Analog zur Erweiterung (siehe oben; vgl. 6.2.3) wird eine Table Function für unpack
benutzt. Die Materialisierung einer ungepackten“ Relation kann hier durch Pipelining
”
vermieden werden (vgl. 7.1.4). Die erweiterte Selektion σϕz (X) kann so formuliert werden:
select * from TABLE( pack( CURSOR
select * from TABLE( unpack( CURSOR (
select * from X order by x1, x2, z )))
WHERE ϕ )))
70
7.2. Übersetzung von Termen
7.2.4. Verbund
Der erweiterte Verbund wird nach dem in 6.2.4 beschriebenen Verfahren erzeugt. Hat
etwa Y die drei Spalten z, x1 und y1 , dann wird der erweiterte Verbund X o
nz Y durch
folgende Anfrage gebildet:
select x1, x2, y1, I_intersect(X.z, Y.z) as z from
X JOIN Y
ON (I_overlaps(X.z, Y.z) = 1 AND X.x1 = Y.x1)
7.2.5. Differenz
Der in 6.2.6 angegebene Algorithmus kann wie pack ebenfalls als Table Function implementiert werden. Haben X und Y das gleiche Schema, dann wird die Differenz X −z Y
folgendermaßen ausgedrückt:
select * from TABLE( minus ( CURSOR (
select * from X LEFT OUTER JOIN Y
ON ( (Y.z is null OR I_overlaps(X.z, Y.z) = 1)
AND X.x1 = Y.x1 AND X.x2 = Y.x2 )
order by x1, x2, X.z, Y.z )))
7.2.6. Vereinigung
Die Vereinigung X ∪z Y benötigt lediglich ein abschließendes pack:
select * from TABLE( pack ( CURSOR (
select * from X UNION Y )))
7.2.7. Durchschnitt
Haben X und Y das gleiche Schema, dann ist der Durchschnitt X ∩z Y ein Sonderfall
des Verbunds (siehe oben). Deshalb wird hierfür keine eigene Übersetzung benötigt.
7.2.8. Gruppierung und Aggregation
Wird nicht nach dem Zeitstempel gruppiert, ist beispielsweise für Γzx1 ,x2 # z=α (X) höchstens ein pack nötig (vgl. 6.2.8).
select * from TABLE( pack ( CURSOR (
select α∗ as z from X
GROUP BY x1, x2 order by x1, x2, z )))
Die erweiterten Aggregationsfunktionen α∗ sind wie in 7.1.2 beschrieben vom Benutzer
entsprechend zu formulieren.
Enthält die Ergebnisrelation keinen Zeitstempel, entfällt auch das abschließende pack.
Für Γzx1 ,x2 # b=α (X) sind keine Table Functions mehr notwendig:
71
7.3. Implementierung des Evaluators
select α∗ as b from X GROUP BY x1, x2
Wird jedoch nach z gruppiert, so ist für Γzz,x1 # b=α (X) die Anwendung von split notwendig. Sei also Xsplitted die durch das in 7.1.5 beschriebene Verfahren materialisierte
Relation. Damit ergibt sich die Anfrage:
select α∗ as b from Xsplitted GROUP BY x1, x2
Zum Abschluß wäre pack notwendig, wenn die Ergebnisrelation den Zeitstempel enthielte
(vgl. oben).
7.3. Implementierung des Evaluators
Um Anfragen auf Grundlage der erweiterten Relationenalgebra an ein temporales Datenbanksystem stellen zu können, wurde ein Programm namens Evaluator“ entwickelt.
”
Der Evaluator1 wertet Ausdrücke einer abgeleiteten Anfragesprache aus indem SQL- und
PL/SQL-Anweisungen erzeugt werden. Auf Wunsch werden diese vom DBMS ausgeführt
und das Ergebnis dargestellt.
Hier wird zunächst die Grammatik der zugrundeliegenden Anfragesprache vorgestellt
und im Anschluß eine Übersicht über die Struktur des Programms gegeben.
7.3.1. Implementierung des Evaluators
Um einen Term in der erweiterten Relationenalgebra auswerten zu können, wurde eine
Anfragesprache auf Grundlage der Algebra entwickelt. Die implementierte Grammatik
dieser Sprache ist in Anhang B in der Erweiterte Backus-Naur-Form (EBNF; [Wir77])
aufgeführt.
Jedem relationalen Operator wird ein Schlüsselwort zugeordnet (etwa project für π).
Für alle Operatoren bis auf die Umbenennung (rename – ρ) existiert eine temporale Variante mit vorangestelltem t“. Das Zeitstempelattribut kann über ein dem Schlüsselwort
”
nachfolgendes ^[Attributname]“ angegeben werden (z.B. tproject^Zeit Produkt,
”
Zeit (R)). Fehlt die explizite Angabe eines Zeitstempels, dann wird das intervallwertige Attribut benutzt, sofern dies eindeutig ist (tproject Produkt, Zeit (R) für R aus
5.3.1).
Um Aggregationen, Erweiterungen und Selektionsbedingungen angeben zu können
werden diese in geschweifte Klammern eingeschlossen. Der Text zwischen den Klammern
wird ohne Weiterverarbeitung in die SQL-Anfrage eingebaut. Geschlossene geschweifte
Klammern müssen quotiert werden: }“ → \}“. Zum Beispiel entspricht dem Term
”
”
ΓZeit
Produkt # b = sum∗ (Preis) (R) der Ausdruck
1
Man könnte den Evaluator als Übersetzer“ bezeichnen, weil ein Term der erweiterten Relationenal”
gebra nach SQL (und PL/SQL) übersetzt wird. Da jedoch im Rahmen des Evaluators diese Übersetzung (auf Wunsch) vom DBMS interpretiert und das Ergebnis (also der Wert der Terms) dargestellt
wird, scheint die Bezeichnung Interpreter“ auch berechtigt zu sein.
”
72
7.3. Implementierung des Evaluators
tgroup by Produkt
aggregate number { sum(Preis * I_count(Zeit)) } as b (R)
Da Projektion, Umbenennung und Erweiterung alle auf select abgebildet werden,
wurde project in der Anfragesprache erweitert: Umbenennung und Erweiterung sind
jetzt auch in der Projektion möglich, z.B.:
project Produkt, Preis, Zeit as VT (R) = rename Zeit as VT (R)
tproject number {Preis * 10} as Preis10, Zeit (R)
project entspricht also mehr einer SQL-select-Anweisung, als der in 3.1.2 definierten
Projektion. Umbenennung und Erweiterung können nun als Spezialfälle der Projektion
implementiert werden.
Bei Verbund, Vereinigung, Differenz und Durchschnitt ist es möglich mehr als zwei
Relationen anzugeben. Die Auswertung erfolgt dabei von links nach rechts, es gilt also minus(X,Y,Z) = minus(minus(X,Y), Z). (Die Auswertungsreihenfolge ist natürlich
nur für die Differenz wichtig, denn Verbund, Vereinigung und Durchschnitt sind assoziative Operatoren.)
Gross- und Kleinschreibung spielt für die Auswertung der Anfragesprache keine Rolle.
Mehrere aufeinanderfolgende Leerzeichen2 werden zu einem einzigen Leerzeichen zusammengefasst.
Die angegebene Grammatik ist eine kontextfreie LL(1)-Grammatik. Die Erkennung
von Ausdrücken der Anfragesprache kann deshalb über die Methode des rekursiven Abstiegs erfolgen ( top-down“; vgl. z.B. [Wir96a]).
”
7.3.2. Ablauf der Anfrageauswertung
Für die Benutzung des Programms gibt es zwei Möglichkeiten: Als Kommandozeilenparameter kann ein Ausdruck der Anfragesprache oder eine Datei übergeben werden. Der
übergebene Ausdruck bzw. die Ausdrücke in der Datei werden dann übersetzt und die
Übersetzung ausgegeben. Ohne Parameter startet der Evaluator in einem interaktiven
Modus. Ähnlich zu sqlplus von Oracle können hier Ausdrücke direkt ausgewertet werden. Im interaktiven Modus oder in einer Datei ist jeder Ausdruck mit einem Semikolon
( ;“) abzuschliessen.
”
Es ergibt sich der in Abbildung 7.1 skizzierte Ablauf: Zunächst werden die Metadaten (vgl. 7.1.6) der temporalen Datenbank ermittelt. Dann kann eine Anfrage in eine
SQL-Anfrage übersetzt werden, wobei eventuell vorher PL/SQL-Funktionen erzeugt und
Relationen explizit materialisiert werden müssen. Der gesamte Code wird dann entweder
ausgegeben oder an das DBMS zur Auswertung übermittelt. Im letzten Fall kann das
Ergebnis dieser Auswertung im interaktiven Modus dargestellt werden.
2
genauer: Whitespace Characters, also auch Tabulatoren und Zeilenwechselzeichen
73
7.3. Implementierung des Evaluators
Zeit
(Tabellennamen, Spaltennamen, Datentypen, ...)
Metadaten
Anfrage
Evaluator
Erweiterung
Intervalle
Übersetzung:
Intervalloperatoren
SQL (und PL/SQL)
Ergebnis oder
Tabellen und Metadaten
Ergebnis
Oracle DBMS
Übersetzung
Abbildung 7.1.: Ablauf der Anfrageauswertung
7.3.3. Struktur des Evaluators
Der Evaluator ist als textbasiertes Programm in Perl realisiert ([WCS96a], [CPAN],
[PerlDoc]). Die Struktur des Evaluators ist in 7.2 dargestellt.
Das ausführbare Programm hat den Namen evaluator.pl. Je nach Aufruf wird die
Benutzerschnittstelle (ui.pm) im interaktiven Modus gestartet oder zur Erzeugung einer
lesbaren Übersetzung benutzt. Über das Modul db.pm werden Datenbankzugriffe abgewickelt. Die Erkennung und Übersetzung eines Ausdrucks geschieht im parser-Modul:
Für jeden Operator der erweiterten Relationenalgebra sind Behandlungsroutinen vorhanden, die im handler-Modul zusammengefasst sind. Diese Routinen nutzen die Schablonen für pack, unpack, split und minus (vgl. 7.1.3), welche durch das Modul templates
gekapselt werden.
evaluator.pl
ui.pm
parser.pm
db.pm
temporal
project restrict
join union ...
handler.pm
regular
project restrict
join union ...
pack
split
templates.pm
unpack
minus
Abbildung 7.2.: Struktur des Evaluators
74
8. Ausblick
For an indefinite time I clung to the machine as it
swayed and vibrated, quite unheeding how I went,
and when I brought myself to look at the dials again
I was amazed to find where I had arrived.
(H.G. Wells, The Time Machine)
Mit dieser Arbeit wurde ein Konzept zur relationalen Modellierung zeitabhängiger Daten geschaffen. Die Definition der erweiterten Relationenalgebra erlaubt die Formulierung
von zeitlichen Zusammenhängen im relationalen Kontext. Durch die Implementierung einer Anfragesprache für temporale Datenbanken auf Grundlage eines bestehenden DBMS
konnte die Realisierbarkeit eines temporalen DBMS belegt werden. Von diesem Standpunkt aus zeichnen sich weitere Möglichkeiten ab:
Änderungsoperationen
Einfügen, Löschen und Ändern läßt sich folgendermaßen mit der erweiterten Relationenalgebra ausdrücken: Sei R eine Relation und t ein Tupel passend zum Schema von R.
Weiterhin sei T eine Relation deren Inhalt nur aus dem Tupel t besteht.
• Einfügen von t in R (tinsert^[Zeitstempel]): R ∪Zeitstempel T
• Löschen von t aus R (tdelete^[Zeitstempel]): R −Zeitstempel T
• Verändern von t in R (tupdate^[Zeitstempel]): löschen und verändert einfügen
Eine Verbesserung kann erreicht werden, indem diese Änderungsoperationen durch bereits bestehende insert-, update- und delete-Befehle implementiert werden statt durch
Vereinigung und Differenz (siehe [DDL2003a] Anhang A).
Zusätzlich kann die Überwachung von zeitlichen Integritätsbedingungen an diese Änderungsoperationen gekoppelt werden ( Trigger“; siehe auch [GL95c]).
”
Vollständige Integration in ein bestehendes DBMS
Um ein temporales DBMS zu schaffen, ist eine Implementierung der erweiterten Algebra in ein bestehendes DBMS notwendig. Die Funktionalität des Evaluators müßte
dazu vollständig in das DBMS integriert werden. Wegen der erläuterten Probleme mit
allgemeinen pack und split Operatoren war dies hier nicht zu realisieren.
Kombination mit räumlichen Datenmodellen
Eine Integration von zeitlichen Konzepten in räumliche Modelle ist häufig wünschenswert. In einem raumzeitlichen Datenmodell können beispielsweise bewegte Objekte dargestellt werden (vgl. z.B. [KPS2003b] oder [Kle2003b]).
75
8. Ausblick
Anfrageoptimierungen
Anfragen an temporale Datenbanken bieten ein großes Optimierungspotential. Zusätzlich
zur Optimierung der klassischen relationalen Operatoren gibt es Verbesserungsmöglichkeiten für Anfragen mit zeitlichem Bezug.
Algebraische Optimierungen
Die Verschiebung von Operatoren innerhalb einer Anfrage kann durch die hier implementierte SQL-Übersetzung beeinträchtigt werden: Eine Verschiebung über einen splitOperator hinweg ist nicht möglich, weil hier ein Zwischenergebnis explizit materialisert
wird.
Theoretisch bilden Pipelined Table Functions keine solche Hürde. Praktisch wird die
Eingaberelation einer Table Function in einem Cursor-Objekt gekapselt. Es ist anzunehmen, dass keine Verschiebung von Operatoren über diese Grenze hinweg stattfindet.
Eine Verschiebung folgender Art wäre dann nicht mehr möglich:
restrict {Bedingung} ( tminus(X, Y) ) =>
tminus( restrict {Bedingung} (X), restrict {Bedingung} (Y) )
Eine Implementierung der Operatoren ohne diese Probleme würde eine schnellere Ausführung temporaler Anfragen bedeuten.
Indexe
Die Unterstützung der zeitlichen Dimension durch eigene Indexe wurde in dieser Arbeit
nicht betrachtet. Eine sortierte Speicherung temporaler Relationen verspricht bereits
einen Geschwindigkeitsgewinn, weil die durch Table Functions realisierten Algorithmen
stets eine Sortierung nach dem Zeitstempel (und eine Partitionierung nach den restlichen
Attributen) verlangen.
Zur Indexierung könnten räumliche Indexe (R-, R∗ -, RSS-Bäume, . . . ) benutzt werden (vgl. [Loc2001a], [Sch2003c], [Kle2003b]): Die benötigte zweite Dimension wäre in
bitemporalen Datenbanken durch den zweiten Zeitstempel gegeben. Sonst kann ein thematisches Attribut oder ein Wert ohne konkrete Semantik als zweite Dimension dienen
(etwa ein festes Intervall oder nochmal der Zeitstempelwert).
Anhand der Intervallgrenzen der Zeitstempel einer Relation kann auch ein B∗ -Baum
aufgebaut werden (siehe [TCG93a] Kapitel 18). Dies entspricht der Vorhaltung der für
split benötigten Punktmenge in einer Baumstruktur.
76
A. Intervalle und Intervalloperatoren
Deklaration des Intervalldatentyps:
create or replace type interval_type as object (
b integer, -- Anfangszeitpunkt
e integer, -- Endzeitpunkt
-static function min return integer, -- kleinstmögliches b
static function max return integer, -- größtmögliches e+1
-constructor function interval_type (b integer, e integer)
return self as result,
-map member function convert return integer
);
Name und Signatur jedes implementierten Intervalloperators:
-- Operatoren für ein einziges Intervall:
I_begin
I_end
I_count
I_toString
I_contains
(i
(i
(i
(i
(n
interval_type) return integer
interval_type) return integer
interval_type) return integer
interval_type) return string
integer, i interval_type) return integer
-- Vergleichsoperatoren:
-- Signatur "(i1 interval_type, i2 interval_type) return integer"
I_included_in
I_includes
I_before
I_begins
I_meets
I_included_in_neq
I_includes_neq
I_after
I_ends
I_overlaps
I_merges
-- intervallwertige Operatoren:
-- Signatur "(i1 interval_type, i2 interval_type) return interval_type"
I_union
I_intersect
I_minus
77
B. Grammatik der Anfragesprache
Der aus der erweiterten Relationenalgebra entwickelten Anfragesprache liegt folgende
Grammatik zugrunde:
B.1. Terminalsymbole
B.1.1. Schlüsselwörter
rename
as
[t]project [t]extend [t]restrict [t]group by aggregate
[t]join
[t]minus [t]union
[t]intersect
B.1.2. Bezeichner und Werte
table column datatype anything
Mit table sind alle Tabellennamen des zugrundeliegenden Datenbankschemas gemeint.
column soll eine Spalte bezeichnen und datatype einen Datentyp. anything ist eine
beliebige Zeichenfolge, wobei geschlossene geschweifte Klammern zu quotieren sind:
}“ → \}“. Dies entspricht den α, β, ϕ in Aggregation, Erweiterung und Selektion (vgl.
”
”
7.2).
B.1.3. Sonderzeichen
, ^ ( ) { }
B.2. Grammatik
term = listop "(" term_list ")" | monop "(" term ")" | table
term_list = term { "," term }
B.2.1. monop
monop = project | rename | extend | restrict | group
rename = "rename" rename_arg
78
B. Grammatik der Anfragesprache
project
extend
restrict
group
=
=
=
=
(
(
(
(
"tproject"
"textend"
"trestrict"
"group"
pack_on
pack_on
pack_on
pack_on
|
|
|
|
"project" )
"extend" )
"restrict")
"group"
)
project_arg
extend_arg
restrict_arg
group_arg
B.2.2. monop-Argumente
rename_arg
project_arg
extend_arg
group_arg
restrict_arg
=
=
=
=
=
renaming
{ ","
projection { ","
extension { ","
"by" column_list
pass_through
renaming
}
projection }
extension }
"aggregate" extension
projection
renaming
extension
= column | renaming | extension
= column " " naming
= datatype " " pass_through " " naming
B.2.3. listop
listop = ( "t" listop_token pack_on | listop_token ) "(" term_list ")"
listop_token = ( "join" | "minus" | "union" | "intersect" )
B.2.4. sonstiges
pass_through = "{" anything "}"
column_list
= column { "," column }
naming
= ( "as" | " " ) column
pack_on
= [ "^" column ]
79
Literaturverzeichnis
[All83a]
J. F. Allen. Maintaining Knowledge about Temporal Intervals. Communications of the ACM, 26(11):832–843, 1983.
[Bei2001a]
F. Beier. Objekt-relationale Realisierung einer temporalen Datenbanksprache. Diplomarbeit, Institut für Informatik, Universität Hannover, Hannover, 2001.
[BJW2000a] C. Bettini, S. Jajodia, S. X. Wang. Time Granularities in Databases, Data
Mining, and Temporal Reasoning. Springer-Verlag, Berlin, 2000.
[CPAN]
Comprehensive Perl Archive Network, 2004.
org/.
URL http://www.cpan.
[Dat2000a]
C. Date. An Introduction to Database Systems, Seventh Edition. AddisonWesley, Reading, MA, 7 Auflage, 2000.
[DD2003]
C. Date, H. Darwen. An Overview and Analysis of TSQL2, 2003. URL
http://www.thethirdmanifesto.com/.
[DDL2003a] C. Date, H. Darwen, N. A. Lorentzos. Temporal Data and the Relational
Model. Morgan Kaufmann, San Francisco, 2003.
[DB2000a]
A. Descartes, T. Bunce. Programming the Perl DBI. Database Programming with Perl. O’Reilly & Associates, Sabastopol, CA, 2000.
[EJS98a]
O. Etzion, S. Jajodia, S. Sripada (Herausgeber). Temporal Databases:
Research and Practice. LNCS 1399. Springer-Verlag, Berlin, 1998.
[Fag79]
R. Fagin. Normal forms and relational database operators. In Proceedings
of the 1979 ACM SIGMOD International Conference on Management of
Data, Seiten 153–160, 1979.
[GL95c]
M. Gertz, U. W. Lipeck. “Temporal” Integrity Constraints in Temporal
Databases. In J. Clifford, A. Tuzhilin (Herausgeber), Recent Advances
in Temporal Databases – Proceedings of the International Workshop on
Temporal Databases, Sept. 1995, Workshops in Computing, Seiten 77–92.
Springer-Verlag, Berlin, 1995.
80
Literaturverzeichnis
[Kle2003b]
C. Kleiner. Modeling Spatial, Temporal and Spatio-Temporal Data in
Object-Relational Database Systems. Doktorarbeit, Hannover, 2003.
[KPS2003b] M. Koubarakis, B. Pernici, H. Schek, M. Scholl, B. Theodoulidis, N. Tryfona, T. Sellis, A. Frank. Spatio-Temporal Databases – The CHOROCHRONOS Approach. Springer Verlag, Berlin, 2003.
[Kuh97a]
B. I. Kuhn. Entwicklung einer Anfragesprache für temporale Datenbanken: Semantik, Ausdrucksfähigkeit und graphische Benutzerschnittstelle.
Diplomarbeit, Hannover, 1997.
[Loc2001a]
U. Löckmann. Erweiterung eines objektrelationalen Datenbankmanagementsystems um verallgemeinerte Suchbäume als Indexstrukturen. Diplomarbeit, Institut für Informatik, Universität Hannover, Hannover, 2001.
[OraAD]
Oracle Database Application Developer’s Guide – Fundamentals, 2004.
[OraDCD]
Oracle Data Cartridge Developer’s Guide, 2004.
[OraDD]
Oracle Database Catalog Views and Data Dictionary, 2004.
[OraDoc]
Oracle Database 10g Release 1 (10.1) Documentation Library, 2004. URL
http://otn.oracle.com/pls/db10g/db10g.homepage.
[OraDW]
Oracle Database Data Warehousing Guide, 2004.
[OraPLSQL] Oracle PL/SQL User’s Guide and Reference, 2004.
[OraSQL]
Oracle Database SQL Reference, 2004.
[OTN]
Oracle Technology Network, 2004. URL http://otn.oracle.com/.
[PerlDoc]
Online Perl Documentation, 2004.
perl5.8.4/pod/perl.html.
[Rei99a]
C. Reinhard. Realisierung einer temporalen Erweiterung von SQL auf
einem objekt-relationalen Datenbankmanagementsystem. Diplomarbeit,
Hannover, 1999.
[Sch2003c]
O. Schweer. Erweiterung eines objektrelationalen Datenbankmanagementsystems um räumliche Verbunde. Diplomarbeit, Institut für Informationssysteme, Universität Hannover, Hannover, 2003.
[Sno95a]
R. T. Snodgrass (Herausgeber). The TSQL2 Temporal Query Language. The Kluwer Int. Series in Engineering and Computer Science. Kluwer
Academic Publishers, Boston, 1995.
81
URL http://www.perldoc.com/
Literaturverzeichnis
[TCG93a]
A. Tansel, J. Clifford, S. Gadia, S. Jajodia, A. Segev, R. Snodgrass (Herausgeber). Temporal Databases: Theory, Design, and Implementation. Database Systems and Applications Series. Benjamin/Cummings, Redwood
City, CA, 1993.
[WCS96a]
L. Wall, T. Christiansen, R. L. Schwartz. Programming Perl (2nd Edition).
O’Reilly & Associates, Cambridge, 2 Auflage, 1996.
[Wel95]
H. Wells. The Time Machine, 1895.
[Wir77]
N. Wirth. What can we do about the unnecessary diversity of notation
for syntactic definitions? Communications of the ACM, 20(11):822–823,
1977.
[Wir96a]
N. Wirth. Grundlagen und Techniken des Compilerbaus. Addison-Wesley
(Deutschland), Bonn, 1996.
[ZCF97a]
C. Zaniolo, S. Ceri, C. Faloutsos, R. Snodgrass, V. Subrahmanian, R. Zicari. Advanced Database Systems. The Morgan Kaufmann Series in Data
Management. Morgan Kaufmann Publishers, San Francisco, 1997.
82
Erklärung
Hiermit versichere ich, dass ich die vorliegende Arbeit und die zugehörige Implementierung selbständig verfasst und dabei nur die angegebenen
Quellen und Hilfsmittel verwendet habe.
Hannover, 27. Juli 2004
Christian Stahlhut
83
Herunterladen