1 Rekursion in Relationalen Datenbanken April 2010 Spiel mit zwei Strukturen Für n ≥ 1 und m=n.2n+2 betrachte die Strukturen 1 2 1 2m 2 3 A 2m-1 B1 m m-1 3 B m+1 m+2 m+3 2m B2 2m-1 A={<i,i+1> 1 ≤ i ≤ 2m-1 } {<2m,1>}, gerichteter zyklischer Graph, und B1 und B2 analog und B=B1 B2. Für x, y in A sei dist(x,y) die Länge eines kürzesten Weges von x nach y, also zB dist(2m,2)=2=dist(2,2m). Analog in B, wobei für x in B1 und y in B2 dist(x,y)=∞ ist. Die gerichtete Distanz gdist(x,y) berücksichtigt noch die Pfeilrichtung durch das Vorzeichen, sodass zB gdist(2m,2)=2= - gdist(2,2m), in B analog (also ∣ gdist(x,y)∣ = dist(x,y), falls beide Wege von x nach y gleichlang sind, soll gdist(x,y) positiv sein). Dann gilt die Dreiecksungleichung dist(x,z) ≤ dist(x,y)+dist(y,z), und wenn alle Distanzen <2n sind, auch die Dreiecksgleichung gdist(x,z) = gdist(x,y)+gdist(y,z). Spielschrittlemma: Sei 1 ≤ k ≤ n-1, a1,...,ak in A und b1,...,bk in B sodass für alle i,j ≤ k mit dist(ai,aj) < 2n+1-k gilt gdist(ai,aj)=gdist(bi,bj), und für alle i,j ≤ k mit dist(bi,bj) < 2n+1-k gilt gdist(ai,aj)=gdist(bi,bj), und ak+1 in A beliebig. Dann gibt es ein bk+1 in B sodass für alle i,j ≤ k+1 mit dist(ai,aj) < 2n-k gilt gdist(ai,aj)=gdist(bi,bj), und für alle i,j ≤ k+1 mit dist(bi,bj) < 2n-k gilt gdist(ai,aj)=gdist(bi,bj). Umgekehrt gibt es für jedes bk+1 in B ein ak+1 in A mit derselben Bedingung. Die Idee ist, dass A und B lokal nicht unterscheidbar sind, wobei Lokalität mit zunehmendem k immer enger gefasst wird. 2 Beweis des Spielschrittlemma: Fall: für alle i ≤ k ist dist(ai,ak+1) ≥ 2n-k. Dann wähle bk+1 in B sodass für alle i ≤ k gilt dist(bi,bk+1) ≥ 2n-k. Beachte dass dies in jedem Falle möglich ist weil es für jedes k Lücken ohne bereits gewählte Elemente gibt von mindestens der Länge m/k, also > m/n = 2n+2. Fall: es gibt ein i ≤ k mit dist(ai,ak+1) < 2n-k. Dann wähle bk+1 in B sodass gdist(ai,ak+1)=gdist(bi,bk+1). Wir zeigen: für j ≤ k und dist(aj,ak+1) < 2n-k gilt gdist(aj,ak+1)=gdist(bj,bk+1). Gemäss Konstruktion gibt es ein i ≤ k mit dist(ai,ak+1) < 2n-k und gdist(ai,ak+1)=gdist(bi,bk+1). Damit ist wegen der Dreiecksungleichung dist(ai,aj) ≤ dist(ai,ak+1)+dist(aj,ak+1) < 2n-k +2n-k =2n+1-k und deshalb nach (Induktions-) Voraussetzung gdist(ai,aj)=gdist(bi,bj). Da alle beteiligten Distanzen < 2n sind, gilt mit gdist(ai,ak+1)=gdist(bi,bk+1) und gdist(ai,aj)=gdist(bi,bj) wegen der Dreiecksgleichung aber auch gdist(aj,ak+1)=gdist(bj,bk+1). Der Beweis dass für j ≤ k und dist(bj,bk+1) < 2n-k gilt gdist(aj,ak+1)=gdist(bj,bk+1) verläuft völlig symmetrisch. Beachte dass der Beweis nur Eigenschaften der Strukturen A und B benutzt hat, welche beiden gemeinsam sind. Deshalb gilt auch die Richtung von bk+1 in B nach ak+1 in A. Spielt man also n Schritte dieses Spieles, mit beliebigem a1 in A und b1 in B beginnend, und in jedem nächsten Schritt ein beliebiges ak+1 in A oder bk+1 in B wählend und ein jeweiliges gemäss Spielschrittlemma korrespondierendes bk+1 in B oder ak+1 in A dazunehmend, so hat man nach n Schritten einander korrespondierende Elemente a1,...,an in A und b1,...,bn in B sodass für alle i,j ≤ n mit dist(ai,aj) < 2 gilt gdist(ai,aj)=gdist(bi,bj). A und B als Modelle binärer Relationen Betrachten wir eine Sprache L die als einziges nichtlogisches Symbol, also nebst der Gleichheit, ein binäres Relationssymbol R(.,.) hat. Dann werden A und B durch die Interpretationen A ⊨ R(a,a’) iff gdist(a,a’)=1 in A, und B ⊨ R(b,b’) iff gdist(b,b’)=1 in B zu Modellen der Sprache L. Nun betrachten wir einen beliebigen Satz von L in pränexer Form mit n Quantoren ≡ Q1x1Q2x2....Qnxn (x1,x2,...,xn), mit Qk{,} und quantorenfrei 3 Behauptung: Dann ist A ⊨ iff B ⊨ , das heisst der Satz ist gültig in A genau dann wenn er gültig ist in B. Beweis: Wir nehmen oBdA an dass A ⊨ und B ⊨ . Die Negation ist dann äquivalent zu Q1’x1Q2’x2....Qn’xn (x1,x2,...,xn), wobei für jedes k Qk’= ist falls Qk= ist und umgekehrt. Wiederum oBdA nehmen wir noch an dass Q1= ist. Wegen A ⊨ x1Q2x2....Qnxn (x1,x2,...,xn) gibt es dann ein a1 in A mit A ⊨ Q2x2....Qnxn (a1,x2,...,xn). Wähle b1 in B beliebig. Wegen B ⊨ x1Q2’x2....Qn’xn (x1,x2,...,xn) gilt dann B ⊨ Q2’x2....Qn’xn (b1,x2,...,xn). Ist im nächsten Schritt Q2 der Quantor, dann nehmen wir ein a2 in A mit A ⊨ Q3x3....Qnxn (a1,a2,x3,...,xn) und ein korrespondierendes b2 in B gemäss Spielschrittlemma, für das dann B ⊨ Q3’x3....Qn’xn (b1,b2,x3,...,xn) gilt weil ja in diesem Fall Q2’= ist. Ist aber Q2’ der Quantor, dann nehmen wir zuerst ein b2 in B sodass B ⊨ Q3’x3....Qn’xn (b1,b2,x3,...,xn), und dann ein korrespondierendes a2 in A gemäss Spielschrittlemma, für das dann A ⊨ Q3x3....Qnxn (a1,a2,x3,...,xn) gilt (wegen Q2= in diesem Fall). Auf diese Art fahren wir weiter, von ak+1 zu bk+1 falls Qk+1 der Existenzquantor ist, und umgekehrt, sodass wir nach n Schritten einander gemäss Spielschrittlemma korrespondierende Elemente a1,...,an in A und b1,...,bn in B haben mit A ⊨ (a1,a2,a3,...,an) und B ⊨ (b1,b2,b3,...,bn). Wegen dem Spielschrittlemma und der Interpretation von R(.,.) in A und B ist dann A ⊨ R(ai,aj) iff B ⊨ R(bi, bj), und weil quantorenfrei ist deshalb für alle i,j ≤ n auch A ⊨ (a1,a2,a3,...,an) iff B ⊨ (b1,b2,b3,...,bn), was einen Widerspruch darstellt. Das bedeutet, dass connectivity nicht ausdrückbar ist in der Logik (erster Stufe), das heisst es gibt keinen Satz der Sprache L welcher in einem Modell A zur Sprache L (={R(.,.)}) genau dann gültig ist, wenn der durch A definierte Graph zusammenhängend ist. Damit ist auch transitive closure nicht ausdrückbar, denn gäbe es eine Formel (x1,x2) die in allen Modellen A mit Elementen a1,a2 in A genau dann gültig wäre, A ⊨ (a1,a2) , wenn <a1,a2> oder <a2,a1> zur transitiven Hülle des durch A definierten Graphen gehören, so wäre x1x2(x1=x2 ∨ (x1,x2)) ein Satz der connectivity ausdrückt. (die transitive Hülle von A, transitive closure, ist A* = {<x,y> x0,x1,...,xn i<n <xi,xi+1> A}) 4 Zusammenhang mit der Relationalen Algebra Relationen werden üblicherweise als Teilmengen von Produkten von Wertebereichen genommen, r D1 D2 D3 und die Operationen via Begriffswelt von Mengen definiert, zum Beispiel die Projektion von r auf D1 und D2 als 1,2(r) = {<t(1),t(2)> t r} D1 D2 Neben der Projektion werden traditionell noch Selektion, Vereinigung, Differenz sowie ein Kreuzprodukt als Basisoperationen zur relationalen Algebra gezählt, und je nach Behandlung der Attribute auch noch ein Renaming, auf das wir uns hier nicht einlassen (mehr dazu mündlich bei Bedarf). Statt dieses Tupelkalkül kann man ein gleichmächtiges Domänenkalkül betrachten, welches formal noch etwas näher an der Logik erster Stufe steht, 1,2(r) = {<x1,x2> x3 <x1,x2,x3> r}, oder, mit Relationen als Sprachelementen, R(.,.,.) in unserem Fall, 1,2(r) = {<x1,x2> x3 R(x1,x2,x3)}. x3 R(x1,x2,x3) ist eine Formel mit den freien Variablen x1 und x2 , und so definiert jede Formel (x1,x2,...,xn) einer Sprache die nur Relationszeichen enthält, eine Abfrage, eine Query respektive eine Sicht auf die Basisdaten R(a1,a2,a3), S(b4,b5,b6,b7,b8), usw, die in Form von Tabellen gespeichert gedacht sind. Eine langweilige formale Analyse, durch so schöne Gleichungen wie {<x1,x2> (x1,x2)} {<x1,x2>(x1,x2)} = {<x1,x2> (x1,x2) (x1,x2)} getragen, zeigt, dass das Kalkül der relationalen Algebra, das Tupelkalkül und das Domänenkalkül logisch sozusagen gleichmächtig sind, woraus man mit dem oben Dargestellten dann schliessen kann, dass in der relationalen Algebra die transitive Hülle nicht darstellbar ist. Deshalb haben die Hersteller von relationalen Datenbank Systemen und 1999 auch der ANSI Standard die Abfragesprache SQL erweitert um eine rekursive Komponente. Die transitive Hülle als Rekursion Für binäre Relationen R(.,.) und S(.,.) bezeichne R∘S die Zusammensetzung R∘S = {<a,b> z(R(a,z) ∧ S(z,b))} Damit lässt sich für eine binäre Relation E(.,.) die transitive Hülle E* = {<x,y> x0,x1,...,xn i<n <xi,xi+1> E} rekursiv beschreiben als E*=E (E*∘E) ( Fixpunkt von f(X)=E (X∘E) ). 5 E* ist die kleinste Menge die E enthält mit <x,y> E* ∧ <y,z> E* → <x,z> E*. Die Gleichung E*=E (E*∘E) ist direkt in SQL übersetzt worden, mit E(Links,Rechts) als WITH ESTAR (Links,Rechts) AS (SELECT Links, Rechts FROM E UNION ALL SELECT x.Links, y.Rechts FROM ESTAR x, E y WHERE x.Rechts=y.Links) SELECT Links, Rechts FROM ESTAR Was aber, wenn das Datenbanksystem keine Rekursion kennt? Weil Rekursion in SQL erst spät erschienen ist und noch nicht alle Datenbanksysteme Rekursion implementiert haben, sind Strukturen untersucht worden, die wenigstens gewisse typische praktische Fragestellungen von transitiven Hüllen ohne Rekursion beantworten können, wie zum Beispiel das “Parts Explosion Problem“, dh finde in einer hierarchischen Struktur zu einem Node alle darunterliegenden. Eine bekanntere unter diesen Strukturen ist das “Nested Set Model“: a 1 14 aa 2 ab 3 4 ac 9 aba 5 10 13 abb 6 7 aca 8 11 12 Die Numerierung erfolgt top-down, left-right (“preorder traversal“). Hier wird in einer Relation zum Beispiel E(Node, Down, Up) festgehalten, also <a,1,14> in E, <aa,2,3> in E, usw. Es ist klar, dass Insert und Delete von Nodes extrem mühsam sind, hingegen gewisse Abfragen einfach respektive erst möglich ohne Rekursion. Vor ein paar Jahren habe ich firmenintern die Frage gestellt bekommen, ob es etwas Aehnliches auch gäbe für nichthierarchische (aber gerichtete azyklische) Graphen, von einem Problem der firmeninternen “Business Data Language“ stammend, und einem Benutzer der ein kleines Datenbanksystem verwenden wollte welches Rekursion nicht kennt. 6 Die Antwort war ein mathematisches Paper “A valuation function for finite directed acyclic graphs“, und ein Strukturvorschlag, nämlich dass man zum gegebenen Graphen (in Form einer Relation E(Links,Rechts)) eine zweite Relation unterhält, Wege(Anfang, Ende, Anzahl), welche zu je zwei Knoten des Graphen, Anfang und Ende, festhalten soll, wieviele verschiedene Wege vom einen zum anderen führen. Aenderungen des Graphen führen zwar ebenfalls zu Aenderungen ganzer Mengen von Tupeln in “Wege“, aber sie sind einfacher zu verstehen. Soll zum Beispiel die Kante <a,b> neu in E eingefügt werden, y b x a so erhöht sich die Anzahl Wege von x nach y um die Anzahl Wege von x nach a, multipliziert mit der Anzahl Wege von b nach y, Anzahlneu(x,y):=Anzahlalt(x,y) + Anzahlalt(x,a).Anzahlalt(b,y), für x,y ∉ {a,b}, usw. Allerdings darf man froh sein, dass anständige Systeme mittlerweile die Rekursion in SQL kennen: Andere Beispiele aus der Praxis: In einem ETL-tool (Extract-Transform-Load) sollen Abhängigkeiten definiert werden zwischen Tabellen, weil wenn eine Tabelle eine referentielle Abhängigkeit zu einer anderen hat, muss diese andere zuerst geladen werden. Weil der Abhängigkeitsgraph E(Nachher,Vorher) hunderte von Einträgen hat, möchte man ihn möglichst redundanzfrei haben, das heisst, bei jedem vorhandenen Pfad x0,x1,...,xn mit n>1 und i<n <xi,xi+1> E 7 im Sinne der Nachher-Vorher Abhängigkeit muss <x0,xn> nicht auch noch festgehalten werden, weil es sich von selbst ergibt. Diese Aufgabenstellung ist die gegenteilige des Suchens der transitiven Hülle, mit E>1 =(E∘E ) (E>1∘E) ist E \ E>1 gesucht, sehr direkt in SQL übersetzt: WITH Egroessereins(Nachher,Vorher) AS (SELECT x.Nachher, y.Vorher FROM E x, E y WHERE x.Vorher=y.Nachher UNION ALL SELECT x.Nachher, y.Vorher FROM Egroessereins x, E y WHERE x.Vorher=y.Nachher) SELECT Nachher, Vorher FROM E EXCEPT ALL SELECT Nachher, Vorher FROM Egroessereins Natürlich wurde in diesem Praxisbeispiel ein strenger mathematischer Beweis dafür gemacht bzw vorgelegt, dass die Lösung nicht zuviel eliminiert aus dem ursprünglich gegebenen Graphen, da natürlich alle Abhängigkeiten eingehalten werden müssen (sonst stürzen die Jobs im ETL tool ab...). Etwas präziser, zwei Nodes die durch einen Pfad verbunden sind, müssen auch nach der Redundanz Elimination noch durch (mindestens) einen Pfad verbunden sein. Ein anderes Praxisbeispiel ist die Beantwortung von Fragen zu Abhängigkeiten von Firmen im Konzern, beispielsweise mit Particip(FinYear,Version,Simtyp,Parent,Child,Share_Perc,Share_Nom) die Frage nach dem maximalen Abhängigkeitslevel, nach indirekten Abhängigkeiten, nach Zyklen, usw. (Version ist zB ’factual’, ’plan’, projections ’P1’, ’P2’, usw).