5 Datenstrukturen für Peripheriespeicher Bei den bisherigen Überlegungen wurde stets vorausgesetzt, daß die Datenstrukturen im Arbeitsspeicher eines Rechners liegen. In diesem Kapitel werden Datenstrukturen behandelt, die sich hauptsächlich für Pseudo-Random-Access-Speicher eignen. Leistungscharakteristika von Pseudo-Random-Access-Speicher: – Die Kapazität ist erheblich größer als die von Arbeitsspeichern (Faktor 1000?). – Die Zugriffsgeschwindigkeit ist erheblich langsamer (Faktor 100000?). Beispiel 5.1 Gegeben sei eine geordnete Menge mit 106 Elementen, die verwaltet werden soll. Ein (fast) vollständiger Binärbaum mit 106 Elementen hat eine Höhe 20. Ein AVL-Baum hätte ungefähr die Höhe 30. Dementsprechend wären bei Verwendung eines AVL-Baum ca. 30 I/O-Operationen pro Zugriff auf den Baum notwendig. Geht man von 12.5 ms pro I/O-Operation aus, so würde der Aufbau des AVL-Baums mehr als vier Tage dauern. 106 30 12:5 = 4:34 1000 3600 24 109 Bemerkungen: Das Problem besteht darin, daß bei der Verwendung von AVL-Bäumen die Übertragungseinheit zwischen Platte und Arbeitsspeicher nur ein einzelner Knoten ist. Da I/O-Operationen aber sehr teuer sind, sollten pro I/O-Operation mehr als nur ein Knoten übertragen werden. Dies bietet sich auch deshalb an, da von einer Platte nicht einzelne Bytes sondern ganze Blöcke gelesen werden. Faßt man nun viele Knoten zu einem großen Block zusammen, entsteht ein Baum mit einem höheren Verzweigungsgrad. x4 x6 x2 x1 x5 x3 x1 x2 x3 x4 x5 x6 x7 x7 Bei einem balancierten Baum mit Verzweigungsgrad 100 reicht eine Höhe von 3 für 106 Einträge. Konsequenz: Verringerung der Aufbaukosten um den Faktor 10. 110 5.1 B-Bäume 5.1.1 Einführung B-Bäume dienen wie AVL-Bäume zur Darstellung und Verarbeitung geordneter Mengen mit Hilfe der Operationen “Suchen”, “Einfügen” und “Löschen”. Man geht davon aus, daß die Transporteinheiten zwischen Arbeitsspeicher und Peripheriespeicher Seiten einer festen Größe (z.B. 1K) sind. Wir nehmen an, daß 2k von Paaren (xi; i) auf eine Seite passen. (x1, a1) (x2, a2) . . . (x2k, a2k) x1; x2; : : : ; x2k entspreche der Sortierreihenfolge. Die assoziierten Informationen i werden ab jetzt weggelassen. Nach dem Einfügen des nächsten Schlüssels x2k+1 ensteht die folgende Situation: x1 x2 . . . x2k x2k+1 Man spaltet nun die Seite in der Mitte und verteilt die Schlüssel wie folgt: xk+1 x1 x2 . . . xk xk+2 xk+3 . . . x2k+1 111 5.1.2 Formale Definition Definition 5.1 (B-Baum) Es seien k; h 2 IN; h 0; k > 0. Ein Baum der Klasse (k; h) ist entweder ein leerer Baum (für h = 0) oder, falls h 1, ein geordneter nicht-leerer Baum, in dem gilt: (1) Jeder Pfad von der Wurzel bis zu einem Blatt hat die gleiche Länge h. (2) Jeder innere Knoten außer der Wurzel hat mindestens k + 1 Söhne, und die Wurzel hat mindestens 2 Söhne, es sei denn, sie ist ein Blatt. (3) Jeder Knoten hat höchstens 2k + 1 Söhne. Definition 5.2 Nmin (k; h) := minf Anzahl der Knoten von T j T 2 (k; h)g Nmax(k; h) := maxf Anzahl der Knoten von T j T 2 (k; h)g Lemma 5.1 Es sei h 1. Dann gilt: 2 Nmin(k; h) = 1 + ((k + 1)h k Nmax(k; h) = 1 1) 1 ((2k + 1)h 1) 2k Beweis: Berechnung über geometrische Reihe. Korollar 5.2 Sei T ein beliebiger Baum 2 (k; h); h 1 mit N (T ) Knoten. Dann gilt: 1 + k2 ((k + 1)h 1 1) N (T ) 21k ((2k + 1)h 1) (2) h logk+1 N (T ) + 2 (1) 112 2 Definition 5.3 (B-Baum (Fortsetzung)) Für die Knoteninhalte eines B-Baums sollen die folgenden Bedingungen gelten: (1) Jeder Knoten außer der Wurzel enthält mindestens 2k Schlüssel. k und höchstens (2) Ist l die Anzahl der Schlüssel in einem inneren Knoten, so hat dieser l + 1 Söhne. (3) In jedem Knoten P sind die in ihm enthaltenen Schlüssel x1; : : : ; xl aufsteigend sortiert. Ist P kein Blatt, so enthält P gerknoten von P . l + 1 Verweise p0; : : : ; pl auf die Nachfol- (4) Es seien P (pi ) die Seite, auf die pi verweist, T (pi) der Unterbaum mit Wurzel P (pi) und S (pi) die Menge der Schlüssel in dem Knoten von T (pi), so gilt: 8y 2 S (p0) : y < xi (b) 8y 2 S (pi) : xi < y < xi+1 für i = 1; : : : ; l 1 (c) 8y 2 S (pl ) : xl < y (a) 113 Definition 5.4 Imin(k; h) := minf Anzahl der Schlüssel von T j T 2 (k; h)g Imax(k; h) := maxf Anzahl der Schlüssel von T j T 2 (k; h)g Lemma 5.3 Sei h 1. Dann gilt: Imin(k; h) = 1 + 2((k + 1)h Imax(k; h) = (2k + 1)h 1 1) 1 2 Beweis: Folgt direkt aus Lemma 5.1 und Definition 5.3. Korollar 5.4 Sei T ein beliebiger B-Baum 2 (k; h); h 1 mit I (T ) Schlüsseln. Dann gilt: h logk+1 I (T ) + 1 Beispiel 5.2 Es seien k = 63; I B-Baum T = 218 250000. log64 I = log1864 = 3 ) h 4 2 (2; 2): 4 10 15 20 1 3 5 6 8 9 11 13 114 16 19 25 30 5.1.3 Durchlauf- und Suchalgorithmus Die Organisation eines Knotens mit veranschaulicht werden: l Schlüsseln kann folgendermaßen p0 x1 1 p1 x2 2 p2 xl l pl Algorithmus 5.1 (Durchlaufalgorithmus für B-Bäume) Es gelten die gleichen Bezeichnungen wie in Definition 5.3. if T (P ) 6= leerer Baum then begin durchlaufe T (p0) for i := 1 to l do begin besuche (xi; i ) durchlaufe T (pi) end end Algorithmus 5.2 (Suche in B-Bäumen) Der folgende Algorithmus beschreibt die Suche nach einem Schlüssel y in T (P ). if y < x1 then suche y in T (p0) if y = xi then fi = 1; : : : ; lg y gefunden if xi < y < xi+1 then fi = 1; : : : ; l suche y in T (pi) if xl < y then suche y in T (pl ) 1g 115 5.1.4 Einfüge-Algorithmus Prinzip: Füge im richtigen Blatt an der richtigen Stelle ein. Falls ein Überlauf in diesem Blatt auftritt, so splitte man dieses Blatt und gebe die Einfügung nach oben weiter. Verfahren: Das Einfügen von Schlüsseln geschieht grundsätzlich in den Blättern. Man durchläuft mit dem neu einzutragenden Schlüssel den B-Baum wie beim Suchen, bis man zu dem Blatt kommt, in das der Schlüssel einzutragen ist. Stehen auf dieser Blattseite weniger als 2k Schlüssel, so trägt man den neuen Schlüssel in diesem Blatt an der entsprechenden Stelle ein. Sind bereits 2k Schlüssel in dem Blatt enthalten, so wird das Blatt gespalten. – Man teilt das Blatt und den neuen Schlüssel in zwei Knoten, die je k Schlüssel enthalten. – Der mittlere Schlüssel wird vom Vater aufgenommen. Der Vater kann ebenfalls 2k Schlüssel enthalten. Dann wird auch er in der gleichen Weise geteilt. Dieser Prozeß kann sich bis zur Wurzel hin fortsetzen. Wird die Wurzel geteilt, so entsteht eine neue Wurzel und der Baum ist um eine Stufe gewachsen. 116 Veranschaulichung des Splits: . . . yl ql yl+1 ql+1 . . . p0 x1 p1 . . . xk pk xk+1 pk+1 . . . x2k p2k x2k+1 p2k+1 Split . . . yl ql xk+1 p yl+1 ql+1 . . . p0 x1 p1 . . . xk pk pk+1 xk+2 pk+2 . . . x2k+1 p2k+1 Durch Einfügen von 7 in den B-Baum von Seite 114 entsteht der folgende Baum: 10 4 7 1 3 5 6 15 20 8 9 11 13 117 16 19 25 30 5.1.5 Kostenanalyse des Such- und Einfügealgorithmus Annahme: Jede Seite, die für eine einzelne Suche oder Einfügung benötigt wird, wird genau einmal aus dem Peripheriespeicher geladen. Bezeichnungen: fmin := minimale Anzahl der zu lesenden Seiten. fmax := maximale Anzahl der zu lesenden Seiten. wmin := minimale Anzahl der zu schreibenden Seiten. wmax := maximale Anzahl der zu schreibenden Seiten. Suchkosten: fmin = 1, falls der Schlüssel auf der Wurzelseite gefunden wird. fmax = h, falls der Schlüssel auf einer Blattseite gefunden wird. wmin = wmax = 0 Einfügekosten: fmin = h; wmin = 1, falls der Schlüssel direkt in einem Blatt eingefügt werden kann. fmax = h; wmax = 2h + 1, falls Splits entlang des Suchpfades bis zur Wurzel hin notwendig sind. 118 Bemerkungen: Der ungünstigste Fall bei den Einfügekosten tritt nur sehr selten auf. Genauer: Beim Aufbau eines B-Baums der Höhe h allein durch Einfügen tritt dieser Fall genau h 1 mal auf. Abschätzung: Beim Erstellen eines B-Baums für eine Menge von I Schlüsseln gibt es weniger als N (I ) 1 Spaltungen, wobei N (I ) die Anzahl der Knoten (bzw. Seiten) des Baums ist. Für N (I ) gilt: N (I ) I k 1 + 1 Jedes Spalten einer Seite verursacht das Schreiben von zwei zusätzlichen Seiten, nämlich der abgespalteten Seite und der modifizierten Vaterseite. Die Anzahl von Seiten, die aufgrund von Spaltungen geschrieben werden müssen, ist also höchstens 2(N (I ) pro Einfügung 2I (N (I ) 1), also höchstens 1), somit im Durchschnitt 2 (( I 1 + 1 1) = 2 (( I 1 ) < 2 I k I k k Der durchschnittliche Aufwand für eine Einfügung ergibt sich dann zu favg = h; wavg < 1 + 2 k Vor allem für größere k werden also die Schreibvorgänge durch Spaltungen nur unwesentlich belastet. 119 5.1.6 Löschalgorithmus Zum Löschen eines Schlüssels x benutzt man die übliche zweigeteilte Vorgehensweise: 1. Suche x. 2. Lösche x. Beim Löschen von x können wieder zwei Fälle auftreten: (a) x ist auf einer Blattseite. Dann entferne x aus diesem Blatt. (b) x ist nicht auf einem Blatt. Dann ersetzte x durch den nächstgrößeren (oder nächstkleineren) Schlüssel y im Baum. Dieser befindet sich sich stets in einem Blatt. Beim Löschen von x aus einem Blatt P können die folgenden Fälle unterschieden werden: (1) Keine Verletzung der B-Baum-Bedingungen – Nach dem Löschen von der Seite P oder – x sind noch mindestens k Schlüssel auf P ist die Wurzel. Dann ist nichts weiter zu tun. 120 (2) Unterlauf – Nach dem Löschen von Seite P , und x sind nur noch k 1 Elemente auf der – auf der Nachbarseite Q sind > k Elemente. Die Seiten P und Q werden konkateniert und anschließend wieder in zwei Seiten gespalten. Der Trennschlüssel im gemeinsamen Vaterknoten von P und Q muß dabei angepaßt werden. Dieser Prozeß kann sich nicht fortsetzen. (3) Konkatenation – Nach dem Löschen von Seite P , und x sind nur noch k 1 Elemente auf der – auf der Nachbarseite Q sind k Elemente. Dann füge die Seiten P und Q sowie den Trennschlüssel in P zusammen und gebe die Seite Q frei. Lösche in dem gemeinsamen Vaterknoten von P und Q den zugehörigen Trennschlüssel. Dieser Prozeß kann sich bis zur Wurzel hin fortpflanzen. 121 Veranschaulichung der Konkatenation: . . . xj-1 p xj q xj+1 . . . q0 z1 q1 . . . zk-1 qk-1 p0 y1 p1 . . . yk pk Konkatenation . . . xj-1 p xj+1 . . . p0 y1 p1 . . . yk pk xj q0 z1 q1 . . . zk-1 qk-1 122 5.1.7 Kostenanalyse des Löschalgorithmus fmin = h; wmin = 1, falls der zu löschende Schlüssel sich auf einem Blatt befindet und im Blatt kein Unterlauf eintritt. f = h; w = 2, falls der zu löschende Schlüssel nicht auf einem Blatt liegt und keine Konkatenation oder Unterlauf auftritt. f = h + 1; w = 3, falls der zu löschende Schlüssel in einem Blatt liegt und ein Unterlauf eintritt. fmax = 2h 1; wmax = h + 1, falls – bei allen Seiten des Suchpfades mit Ausnahme der ersten beiden eine Konkatenation erforderlich ist, – beim Nachfolger der Wurzel ein Unterlauf eintritt und – die Wurzelseite verändert werden muß. Grobe Abschätzung für die durchschnittlichen Schreibkosten: Wenn ein Schlüssel in einem inneren Knoten gelöscht werden soll, fallen zwei Schreibzugriffe an. Bei einem Unterlauf im Blatt fallen zwei zusätzliche Schreibzugriffe an. Bei sukzessivem Löschen können höchstens I k 1 Konkatenationen auftreten. Somit fallen im Durchschnitt höchstens 2 I k 1 I1 < k2 für Konkatenationen notwendige Schreibzugriffe pro Löschvorgang an. Damit gilt für den durchschnittlichen Gesamtaufwand pro Löschvorgang: wavg 4 + k2 123 5.1.8 Speicherausnutzung, Optimale Seitengröße Die Effizienz von B-Bäumen wird durch den Parameter k mitbestimmt. Es stellt sich die Frage, wie k zu wählen ist, damit die B-BaumAlgorithmen möglichst effizient sind. Der Gesamtaufwand setzt sich zusammen aus: – dem Aufwand für eine einzelne Seite und – der Anzahl der zu bearbeitenden Seiten, die im wesentlichen durch die Höhe h des Baumes bestimmt ist. Aufwand zur Bearbeitung einer Seite: : fester Zeitanteil pro Seite, z.B. die Zugriffszeit. : Übertragungszeit für ein Tripel (xi; i; pi). : Konstante, derart, daß der Aufwand für die Suche in einer Hauptspeicherseite log n beträgt. Hierbei ist n die Anzahl der Schlüssel in der Seite. : Belegungsfaktor einer Seite, 1 2. Der Aufwand zur Bearbeitung einer Seite beträgt damit: + (2k + 1) + log(k + 1) h sei die durchschnittliche Zahl von Seiten, die für eine einzelne Operation in den Hauptspeicher gebracht und geschrieben werden müssen. Der gesamte Zeitaufwand T für eine Operation ist demnach: T = h( + (2k + 1) + log(k + 1)) 124 Die Höhe wird gemäß Korollar 5.4 approximiert durch h logk+1(I + 1) Damit erhält man die folgende zu minimierende Funktion: T (k) logk+1(I + 1)( + (2k + 1) + log(k + 1)) Ableiten nach k führt zu: + (2k + 1) + 2 k + 1 log( k + 1) =! 0 bzw. k + 1 = 2 log(k + 1) (2k + 1) =: f (k; ) Man beachte, daß die Funktion f nicht von I , d.h. der Anzahl der Schlüssel abhängt. Dies bedeutet, daß man auch für einen sich dynamisch änderndern B-Baum eine optimale Seitengröße festlegen kann und diese nicht laufend anzupassen braucht. Für = 50 ms und = 90 s ist 64 k 128 eine vernüftige Wahl. 125 5.1.9 Verallgemeinerung für Indexelemente variabler Länge Bisher wurde davon ausgegangen, daß die Paare (x; ) und damit auch die in einem B-Baum gespeicherten Tripel Länge haben. (x; ; p) eine feste Dadurch ergab sich für eine gegebene Seitengröße ein festes k. Die Grundschemata der B-Baum-Algorithmen können aber auch bei einer variablen Länge der Indexelemente beibehalten werden. Die Variabilität kann sowohl durch die Schlüssel x als auch durch die assoziierten Informationen entstehen. Der Einfachheit halber sprechen wir von variablen Schlüssellängen (meinen aber beides). In variablen Fall wird das Balancierungskriterium etwas allgemeiner. I.d.R. steuert man bei variablen Schlüssellängen die Ausgeglichenheit des B-Baums über eine minimale und maximale Belegung der Seiten. Einfügen und Splitten geschehen analog zu fixen Schlüssellängen, d.h. wenn in einem Blatt kein Platz mehr für das einzufügende Paar (x; ) ist, dann wird das Blatt geteilt und der Schlüssel in der Mitte (in bezug auf die Gesamtlänge) wandert in den gemeinsamen Vater. Nach dem Splitten sind die beiden Seiten zu fast 50% belegt. Dieser Vorgang kann sich bis zur Wurzel hin fortpflanzen. 126 Löschen: Löschen ist bei variablen Schlüssellängen etwas problematischer als bei fixen Schlüssellängen. Befindet sich der zu löschende Schlüssel x in einem inneren Knoten, so wird er durch den nächstgrößeren Schlüssel y ersetzt. Ist y länger als x, so kann es nach der Ersetzung von x durch y im inneren Knoten zu einem Überlauf kommen. Dies kann durch einen Split behoben werden. Ist y kürzer als x, so kann es nach der Ersetzung zu einem Unterlauf oder gar einer Konkatenation im inneren Knoten kommen. Ebenso kann der Ausgleich eines Unterlauf einen Überlauf, einen weiteren Unterlauf oder eine Konkatenation im Vater verursachen. Im Gegensatz zu fixen Schlüssellängen kann sich also auch ein Unterlauf bis zur Wurzel hin fortpflanzen. Der Aufwand zur Rebalancierung ist aber nach wie vor höchstens proportional zur Baumhöhe. 127