Implementierung relationaler Operationen Udo Kelter 30.11.2002 Zusammenfassung dieses Lehrmoduls Aus der formalen Definition der relationalen Operationen ergeben sich unmittelbar triviale Implementierungen. Diese sind in vielen Fällen sehr ineffizient, besonders bei Selektionen und Verbunden. Dieses Lehrmodul stellt effizientere Implementierungen vor; meist werden hierbei Primär- oder Sekundärindexe ausgenutzt. obligatorisch: – Das relationale Datenbankmodell Stoffumfang in Vorlesungsdoppelstunden: 1 0.8 Implementierung relationaler Operationen 2 Inhaltsverzeichnis 1 Einleitung 3 2 Triviale Implementierungen 3 3 Exkurs: Indexstrukturen 3.1 Primärindexe . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2 Sekundärindexe . . . . . . . . . . . . . . . . . . . . . . . . . . 5 5 7 4 Optimierungen der Selektion 8 5 Optimierungen der Projektion 11 6 Optimierungen der Verbundberechnung 11 Literatur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Glossar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 16 16 c 2002 Udo Kelter Stand: 30.11.2002 Dieser Text darf für nichtkommerzielle Nutzungen als Ganzes und unverändert in elektronischer oder gedruckter Form beliebig weitergegeben werden und in WWW-Seiten, CDs und Datenbanken aufgenommen werden. Jede andere Nutzung, insb. die Veränderung und Überführung in andere Formate, bedarf der expliziten Genehmigung. Die jeweils aktuellste Version ist über http://kltr.de erreichbar. Implementierung relationaler Operationen 1 3 Einleitung Die Bedeutung der relationalen Operationen kann in sehr präziser, aber dennoch abstrakter Weise unter Benutzung mathematischer Begriffe (insb. der Mengenlehre) definiert werden, s. [RDBM]. Diese Definitionen kann man auch direkt in triviale Implementierungen umsetzen. Man erkennt aber leicht, daß diese trivialen Implementierungen teilweise extrem ineffizient und daher inpraktikabel sind. In diesem Lehrmodul betrachten wir effizientere Implementierungen; diese beruhen teilweise auf Indexen. Wir betrachten hier nur die Implementierung einzelner relationaler Operationen; die Abarbeitung komplexer algebraischer Ausdrücke wird in einem separaten Lehrmodul behandelt [AVO]. Ferner betrachten wir nur die wichtigsten Operationen der relationalen Algebra, wir konzentrieren uns auf Selektionen und Verbunde. Dieses Lehrmodul erhebt nicht den Anspruch, die enorme Vielfalt an Optimierungsmöglichkeiten und Indexstrukturen auch nur annähernd zu repräsentieren. Ziel ist es vielmehr, anhand der simplen Optimierungstechniken zu zeigen, welche Größenordnung des Rechenaufwands für die relationalen Operationen erreichbar ist. 2 Triviale Implementierungen Die mathematischen Definitionen der relationalen Operationen können unmittelbar in die folgenden “trivialen” Implementierungen umgesetzt werden. Wir bestimmen noch jeweils den Aufwand unter der Annahme, daß die betroffenen Relationen n bzw. m Tupel enthalten. Selektion: Man durchläuft alle Tupel einer Relation, wertet jedesmal das Selektionsprädikat aus und gibt ggf. das Tupel aus. Der Aufwand hat die Größenordnung O(n). Wenn A Identifikationsschlüssel ist, muß bei einer Selektionsbedingung der Form σA=x im Durchschnitt die halbe Relation durchlaufen werden, bis das gesuchte Tupel gefunden ist, sofern alle vorhandenen Schlüsselwerte gleichhäufig gesucht werden. Bei großen Relationen ist c 2002 Udo Kelter Stand: 30.11.2002 Implementierung relationaler Operationen 4 dies sehr ineffizient. Projektion: Man durchläuft alle Tupel einer Relation und gibt die gewünschten Attribute aus. Der Aufwand hierfür ist exakt n, die Relation muß komplett durchlaufen werden. Wenn zusätzlich eine Duplikateliminierung verlangt ist, muß die Ergebnismenge sortiert werden (zusätzlicher, insg. dominierender Aufwand in der Größenordnung O(n*log(n))). Wenn die Projektionsattribute einen Identifizierungsschlüssel enthalten, können natürlich keine Duplikate auftreten, und eine Duplikateliminierung ist überflüssig. Mengenoperationen: Die Algorithmen für die Mengenoperationen sind ebenfalls trivial. Sofern die Mengen schon geeignet sortiert sind, ist der Aufwand linear, ansonsten kommt der Aufwand für die Sortierung hinzu. Kreuzprodukt: Man durchläuft geschachtelt beide Relationen und gibt jeweils die Konkatenation der beiden aktuellen Tupel aus. Der Aufwand hat die Größenordnung O(n*m), wenn n bzw. m die Zahl der Tupel in den beiden Relationen ist. Verbunde: Man kann den Verbund auf ein Kreuzprodukt, gefolgt von einer Selektion und einer Projektion zurückführen (s. Abschnitt 3.6.2 in [RDBM]). Den größten Aufwand darin wird i.a. das Kreuzprodukt verursachen. Diese trivialen Implementierungen sind, wie die vorstehenden Größenordnungsangaben für den Aufwand zeigen, oft sehr ineffizient. Dies gilt vor allem für die Verbundbildung. I.f. besprechen wir daher diverse Optimierungsmaßnahmen für die einzelnen Operationen. Optimierungsziele. Vorrangiges Optimierungsziel bei der Implementierung der elementaren Operationen ist eine möglichst geringe Zahl von Plattenzugriffen. Die CPU-Belastung spielt nur eine sekundäre Rolle. c 2002 Udo Kelter Stand: 30.11.2002 Implementierung relationaler Operationen 3 5 Exkurs: Indexstrukturen Indexe spielen für effiziente Implementierungen der Selektion und des Verbunds eine große Rolle. Die Optimierungsmöglichkeiten hängen dabei stark von den Strukturen innerhalb der Indexe ab; wir geben daher vorab einen Überblick über die wichtigsten Indexstrukturen und deren Eigenschaften. 3.1 Primärindexe Primärindexe sind Datenstrukturen, die in die “Nutzdaten” eingebettet sind und die Primärschlüssel realisieren. Bis auf wenige Ausnahmen kann ein Datenbestand nur einen Primärindex haben. B*-Bäume. B- bzw. B*-Bäume sind bekanntlicherweise Baumstrukturen, die auf die Besonderheiten einer blockorientierten Speicherung adaptiert sind. Ihre wesentlichen Eigenschaften sind: – Die Struktur der Indexblöcke hat einen sehr hohen Verzweigungsgrad (typischerweise >10), d.h. die Zahl der Indexblöcke ist signifikant kleiner als die Zahl der Primärdatenblöcke. Die Baumstruktur hat meist nur 3 - 4 Ebenen. – Bei der Suche nach einem Satz mit gegebenem Primärschlüsselwert müssen zunächst die Indexblöcke durchlaufen werden. Wegen der geringen Anzahl können aber meist die oberen Ebenen der Struktur im Hauptspeicher gepuffert werden, d.h. hierdurch werden nur sehr wenige oder keine Blockübertragungen verursacht. – B*-Bäume ermöglichen effiziente Implementierungen von Intervallabfragen und von sequentiellen Durchläufen in steigender oder fallender Reihenfolge der Primärschlüsselwerte. – Verarbeitet man eine Menge von Sätzen in steigender oder fallender Reihenfolge ihrer Primärschlüsselwerte, so wird jeder Index- oder Primärdatenblock nur einmal von der Platte gelesen. c 2002 Udo Kelter Stand: 30.11.2002 Implementierung relationaler Operationen 6 Hash-Verfahren. Die Grundidee des Hash-Verfahrens, die zu speichernden Einheiten in einem Array zu verwalten, läßt sich direkt auf die Verhältnisse bei eine Speicherung auf Platte adaptieren: Als Array-Elemente wählt man Blöcke (bzw. Seiten), die ja ebenfalls direkt adressierbar sind. In der Regel passen mehrere Sätze in einen Block; man benötigt also noch interne Verwaltungsstrukturen innerhalb eines Blocks. Die grundlegenden Hash-Verfahren sehen bei einem Tabellenüberlauf ein komplettes Rehashing vor; im Hauptspeicher und bei kleinen Datenbeständen mag das gehen, bei großen Datenbeständen auf Platte ist dieses Vorgehen völlig unrealistisch. Beim offenen Hashing können sehr lange Überlaufketten entstehen, was ebenfalls unattraktiv ist. Eine praktikable Lösung dieses Problems besteht darin, in zwei Schritten über eine Blockadreßtabelle auf Blöcke zuzugreifen: Schlüsselwert k Hashfunktion hash(k) Seiten/Blöcke Blockadreßtabelle Abbildung 1: Erweiterbares Hashing 1. Schritt: Berechnung einer Position in der Blockadreßtabelle 2. Schritt: Zugriff auf den Datenblock und Durchsuchen desselben Die Blockadreßtabelle sollte ca. 100 bis 1000 Mal kleiner als die Datenbank gewählt werden und möglichst im Hauptspeicher gehalten werden. Verschiedene Einträge in der Blockadreßtabelle können auf den gleichen Datenblock verweisen, d.h. in einem Block befinden sich Sätze mit unterschiedlichem Hash-Wert. Schlecht gefüllt Datenblöcke können so vermieden werden. Die Blockadreßtabelle kann mit vertretbarem Aufwand reorganisiert werden, ohne alle Datenblöcke zu kopieren; daher nennt man dieses Verfahren auch erweiterbares Hac 2002 Udo Kelter Stand: 30.11.2002 Implementierung relationaler Operationen 7 shing. Auf die möglichen Varianten von Reorganisationen und die Behandlung von Blocküberläufe gehen wir hier nicht weiter ein. Der prinzipielle Vorteil von Hash-Verfahren gegenüber Suchbäumen, daß keine Indexknoten durchlaufen werden müssen, bleibt erhalten: Im Idealfall wird über den Hashwert eines vorgegebenen Primärschlüsselwerts sofort der Block gefunden, der den zugehörigen Satz enthält. Je nach der Überlaufbehandlung und der Änderungshäufigkeit im Datenbestand geht dieser Vorteil aber teilweise wieder verloren; auf Details gehen wir hier nicht ein. Hash-Verfahren unterstützen keine Intervallabfragen. 3.2 Sekundärindexe Sekundärindexe existieren separat vom Primärdatenbestand und unterstützen insb. auch die Suche nach nicht-identifizierenden Attributen und Attributkombinationen. Ein Sekundärindex unterstützt die Suche für eine Attributmenge A (meist ist A einelementig); A wird auch als zugehöriger Suchschlüssel bezeichnet. Konzeptuell ist der Sekundärindex eine Datenstruktur, die für jede Wertekombination der Attribute aus A eine Trefferliste liefert. Die Trefferliste enthält in irgendeiner Form Referenzen auf die Sätze, bei denen die Wertekombination der Attribute auftritt. Beispielsweise könnte es zu der Relation lieferungen einen Sekundärindex für das Attribut Kundennummer geben; der Sekundärindex würde dann die Suche nach den Lieferungen an einen Kunden unterstützen. Sekundärindexe stellen die Originaldaten in gewisser Weise umgekehrt (invertiert) dar; ein normales Tupel t enthält die Information, daß ein Attribut A den Wert x hat, ein Index zum Attribut A enthält die Information, daß der Wert x u.a. im Tupel t auftritt. Datenbestände mit Index werden daher auch invertiert genannt. Eine naheliegende Wahl für die Referenzen in den Trefferlisten sind Primärschlüsselwerte. Die Trefferliste ist dann zu durchlaufen, und für jeden Eintrag kann über den Primärindex auf den entsprechenden Satz zugegriffen werden. c 2002 Udo Kelter Stand: 30.11.2002 Implementierung relationaler Operationen 8 Aktualisierung von Sekundärindexen. Wie schon erwähnt enthalten Sekundärindexe im Prinzip redundante Daten; werden die Primärdaten geändert, müssen die Sekundärindexe entsprechend angepaßt werden. Wird z.B. beim Tupel t der Wert des Attributs A von x1 nach x2 geändert, muß im Sekundärindex für den Suchschlüssel A im Eintrag für x1 die Referenz auf t gelöscht und im Eintrag für x2 die Referenz auf t eingefügt werden. Wenn die beiden Einträge nicht zufällig in der gleichen Seite liegen, müssen also wenigstens 2 Seiten geschrieben1 und, falls sie nicht schon gepuffert waren, vorher gelesen werden. Änderungsoperationen werden also durch Sekundärindexe deutlich teurer. Bei einer hinreichend hohen Änderungshäufigkeit können sich (zu viele) Sekundärindexe daher insgesamt negativ auf die Systemleistung auswirken. 4 Optimierungen der Selektion Bei der Selektion können Indexe unter bestimmten Umständen vorteilhaft ausgenutzt werden. Wir müssen hierzu verschiedene Formen von Selektionsbedingungen unterscheiden: Selektionsbedingung der Form σA=x . Wenn das Attribut A der Primärschlüssel ist, kann sehr effizient mit konstantem Aufwand (also O(1)) auf den einen Treffer zugegriffen werden. Sofern ein Sekundärindex für das Attribut A vorliegt, hängt es von bestimmten Umständen ab, ob es sich lohnt, den Index auszunutzen. Der Einsatz lohnt nicht bei einer geringen Selektivität des Attributs. Um dies präziser zu fassen, benötigen wir einige Größen; sei sr der durchschnittliche Speicherplatzbedarf eines Tupels (incl. Hilfsdaten) der Relation r 1 Das Schreiben kann eine Zeitlang aufgeschoben werden, da die Indexdaten aus den Primärdaten rekonstruiert werden können. Hier bestehen komplexe Zusammenhänge mit der Transaktionsverarbeitung, auf die wir hier nicht eingehen können. c 2002 Udo Kelter Stand: 30.11.2002 Implementierung relationaler Operationen 9 b die Größe eines Blocks bf = ⌊b / sr ⌋ der Blockungsfaktor, also die Zahl der Sätze, die in einen Block passen Beispiel: mit b=4096 Bytes und sr =200 ist bf=20. |r| die Zahl der Tupel in der Relation r V(A,r) die Zahl der verschiedenen Werte, die Attribut A in Relation r annimmt Wenn man vereinfachend annimmt, daß jeder Wert des Attributs A gleichhäufig auftritt, dann liefert eine Selektion der Form σA=x ungefähr | r | / V(A,r) Tupel zurück, oder anders gesagt den V(A,r)-ten Teil der Relation r. Diesen “Verkleinerungsfaktor” bezeichnet man auch als die Selektivität des Attributs A. Wenn nun V(A,r) ≤ bf ist, die Selektivität also kleinergleich dem Blockungsfaktor ist, ist unter der Annahme, daß die Treffertupel gleichmäßig über die Blöcke verstreut liegen, in jedem Block wenigstens ein Treffertupel vorhanden, d.h. praktisch alle Blöcke müssen übertragen werden. Durch den Einsatz des Sekundärindex können dann also keine Blockübertragungen eingespart werden. Im Gegenteil führt die Benutzung des Sekundärindex zu zusätzlichen Blockübertragungen für Blöcke des Sekundärindex. Hieraus folgt - insb. wenn man zusätzlich den Änderungsaufwand für den Sekundärindex berücksichtigt -, daß Sekundärindexe für Attribute mit geringer Selektivität nicht sinnvoll sind. Selektionsbedingung der Form σA>x ∧ A<y (Intervallabfrage zum Attribut A). Sofern die internen Zugriffsmethoden auch Intervallabfragen unterstützen (z.B. bei B-Bäumen), können auch diese effizient bearbeitet werden, wobei hier der Aufwand linear von der Größe der Treffermenge abhängt. Entscheidend ist hier die kompakte (clusternde) Speicherung von Sätzen bzw. Tupeln mit aufeinanderfolgenden Schlüsselwerten innerhalb eines Blocks. Hierdurch braucht für jeweils bf Sätze nur ein Block übertragen zu werden (mit Ausnahme der “Randblöcke”). c 2002 Udo Kelter Stand: 30.11.2002 Implementierung relationaler Operationen 10 Selektionsbedingung der Form σA>x . Bei Selektionskriterien, in denen Vergleichsoperatoren wie > verwendet werden, wird unter bestimmten Gleichverteilungsannahmen im Schnitt die halbe Relation zurückgeliefert, d.h. im Sinne der vorstehenden Bemerkungen liegt eine extrem schlechte Selektivität vor. Eine wesentliche Aufwandsreduktion gegenüber dem sequentiellen Durchsuchen der Relation ist also bei >-Vergleichen durch Indexe nicht möglich. Selektionsbedingung mit mehreren Attributen und einem Index. Wenn das Selektionskriterium die Form σA=x ∧X hat und für A ein Primär- oder Sekundärindex vorhanden ist, kann die undVerknüpfung in der Selektion konzeptionell auf die Schachtelung σX (σA=x (...)) zurückgeführt werden, d.h. unter Ausnutzung des Index werden nur relativ wenige Tupel von der Platte gelesen; für diese Tupel werden dann die weiteren Bedingungen direkt überprüft. Vorteilhaft ist es in diesem Zusammenhang, wenn Tupel, die im gleichen Block liegen, hintereinander verarbeitet werden und so letztlich jeder Block nur einmal übertragen werden muß. Werden die Tupel in einem B*-Baum gespeichert, so kann man dies erreichen, indem man die Tupel nach ihren Primärschlüsselwerten sortiert verarbeitet. Selektionsbedingung mit mehreren Attributen und mehreren Indexen. Sind mehrere elementare Bedingungen vorhanden, bei denen jeweils ein Sekundärindex für das auftretende Attribut vorhanden ist, so können ggf. zunächst, bevor auf die eigentlichen Daten zugegriffen wird, Trefferlisten für die einzelnen Elementarbedingungen erstellt und die logischen Verknüpfungen zwischen den Elementarbedingungen durch entsprechende Mengenoperationen realisiert werden. Speziell bei und-Verknüpfungen kann es sein, daß die Treffermenge auf diese Weise deutlich verkleinert wird und weniger Blöcke übertragen werden müssen c 2002 Udo Kelter Stand: 30.11.2002 Implementierung relationaler Operationen 5 11 Optimierungen der Projektion Bei der Projektion läßt sich der Aufwand, die komplette Eingaberelation zu verarbeiten und ggf. Duplikate zu eliminieren, im Prinzip nicht reduzieren. Der Aufwand für das Lesen der Eingaberelation kann allerdings komplett vermieden werden, wenn es sich bei der Eingaberelation um ein Zwischenergebnis einer vorherigen Operation handelt, z.B. einer Selektion oder einem Verbund, indem man die Projektion in die vorgeschaltete Operation integriert und gleich bei der Generierung des Zwischenergebnisses berücksichtigt. Konzeptionell handelt es sich dann um neue, kombinierte Operationen. Die Annahme, daß eine Projektion nach einer anderen Operation erfolgt, ist sehr häufig schon bei der Formulierung einer Abfrage erfüllt und kann oft vom Optimierer durch Umstellung der Anfrage erreicht werden. 6 Optimierungen der Verbundberechnung Verbunde sind häufig, da infolge der Normalisierung vielfach Daten, die für eine Anwendung benötigt werden, auf mehrere Relationen verteilt werden. Die Ineffizienz des Grundalgorithmus für den Verbund ist daher äußerst nachteilig, und es sind diverse Varianten und Optimierungsmaßnahmen entwickelt worden. Einfaches Iterieren. Die oben skizzierte Implementierung wird auch als Einfaches Iterieren oder nested loop join bezeichnet und ist in Varianten für den natürlichen Verbund, den Θ-Verbund, die äußeren Verbunde und das Kreuzprodukt anwendbar. In vereinfachter Form handelt es sich um folgende geschachtelte Schleife: for each tuple t1 in r1 for each tuple t2 in r2 pruefe, ob <t1|t2> in Ergebnismenge kommt c 2002 Udo Kelter Stand: 30.11.2002 Implementierung relationaler Operationen 12 Wenn z.B. | r1 | = 10.000 und | r2 | = 200 ist, dann wird die innere Anweisung 2.000.000 Mal durchlaufen. Eine wichtige Frage ist, ob die Relation r2 immer wieder neu von der Platte gelesen werden muß und somit Blockübertragungen notwendig werden. Bei den heute üblichen Hauptspeichergrößen kann man erhebliche Datenmengen im Hauptspeicher puffern. Wenn wir wenigstens eine Relation (also die kleinere) komplett im Hauptspeicher puffern können, tun wir das und brauchen somit beide Relationen nur einmal zu lesen. Relationen können aber trotzdem zu groß sein, um komplett gepuffert werden zu können. Die folgenden Überlegungen gehen zur Vereinfachung davon aus, daß immer nur ein Block gepuffert werden kann. Sofern die Tupel der Relation r2 in zufälliger Reihenfolge, also gestreut im entsprechenden DB-Segment, verarbeitet werden, muß i.a. für jedes Tupel ein Block übertragen werden. Dies ist extrem ungünstig, in unserem obigen Beispiel kommen wir auf 2.000.000 Blockübertragungen. Eine offensichtliche Verbesserung liegt darin, die Relation r2 geblockt zu speichern - falls sie es nicht sowieso ist, lohnt es sich, eine temporäre Kopie anzulegen - und sie bei jedem Durchlauf in physischer Reihenfolge zu lesen. Die Zahl der Blockübertragungen reduziert sich dann um den Blockungsfaktor. In unserem Beispiel würde r2 bei einem Blockungsfaktor 20 nur 10 Blöcke belegen, bei 10.000 Schleifendurchläufen wären 100.000 Blockübertragungen nötig. Blockorientiertes Iterieren. Eine weitere deutliche Verbesserungsmöglichkeit ergibt sich, wenn auch r1 einen hohen Blockungsfaktor hat. Anstatt nun für jedes Tupel in r1 jeweils die ganze Relation r2 zu lesen, lesen wir immer einen Block in r1 und r2 und verarbeiten alle darin enthaltenen Paare von Tupeln: for each block B1 in r1 for each block B2 in r2 for each tuple t1 in B1 c 2002 Udo Kelter Stand: 30.11.2002 Implementierung relationaler Operationen 13 for each tuple t2 in B2 pruefe, ob <t1|t2> in Ergebnismenge kommt Die Zahl der Blockübertragungen reduziert sich dann noch einmal um den Blockungsfaktor. Wenn in unserem Beispiel auch r1 einen Blockungsfaktor 20 hat, also 500 Blöcke belegt, sind nur noch 5.000 Blockübertragungen erforderlich. Wir haben bisher unterstellt, daß pro Relation genau ein Block gepuffert werden kann, was ziemlich unrealistisch ist. Sind insgesamt n Blöcke für die Pufferung verfügbar, so bilden wir in beiden Relationen jeweils Abschnitte von n/2 Blöcken und behandeln jeweils einen Abschnitt wie einen Block im obigen Algorithmus. Verbundberechnung mit Index. Beim einfachen und blockorientierten Iterieren wird die zweite Relation im Prinzip immer wieder sequentiell nach Verbundpartnern für das aktuell betrachtete Tupel der ersten Relation durchsucht. Die lineare Suche ist das ineffizienteste Suchverfahren. Sofern für die zweite Relation ein Primär- oder Sekundärindex für das Verbundattribut (bzw. die Verbundattribute) vorliegt, ist mit dessen Hilfe eine wesentlich effizientere Suche möglich (s. Bild 2). U.U. lohnt es sich, einen Index temporär aufzubauen. r1 A Index für r2 r2 A Abbildung 2: Verbundberechnung mit Index Diese Verbundberechnung mit Index ist im sehr häufigen Fall anwendbar, daß der Verbund über einen Fremdschlüssel gebildet wird; der Fremdschlüssel ist dann in der anderen Relation Primärschlüssel. Ein c 2002 Udo Kelter Stand: 30.11.2002 Implementierung relationaler Operationen 14 Beispiel hierfür ist der schon früher betrachtete Verbund lieferungen 1 kunden. Wie schon früher erwähnt lohnt der Einsatz von Indexen nicht, wenn das unterstützte Attribut eine schlechte Selektivität hat. Bei großen, nicht pufferbaren Relationen und geringer Selektivität des Verbundattributs entstehen allerdings immens große Resultate, die mit hoher Wahrscheinlichkeit die verfügbaren Ressourcen überlasten, so daß derartige Abfragen ohnehin unrealistisch sind. Misch-Verbund (Merge Join). Sofern bei einem Verbund r1s das Attribut A Verbundattribut ist und sowohl r als auch s nach A sortiert gespeichert sind, kann der Verbund unter gewissen Bedingungen wie beim Misch-Algorithmus in einem einzigen parallelen Durchlauf durch die beiden Relationen konstruiert werden. r1 A r2 A x x x x x Abbildung 3: Misch-Verbund Hierzu wird in einer Schleife der jeweils nächstgrößere, in beiden Relationen auftretende Wert des Verbundattributs bestimmt2 . In beiden Relationen bilden die Tupel, bei denen dieser Wert auftritt, jeweils ein “Abschnitt”. Alle Tupel in den beiden Abschnitten müssen paarweise kombiniert und ausgegeben bzw. weiterverarbeitet werden. Sofern das Verbundattribut eine hohe Selektivität hat, sind diese Abschnitte kurz und können wahrscheinlich komplett gepuffert werden. Andernfalls werden diese Abschnitte entsprechend lang - im Extremfall kann die ganze Relation einen einzigen Abschnitt bilden -, d.h. 2 Werte, die nur in einer der Relationen auftreten, müssen nur bei äußeren Verbunden betrachtet werden. c 2002 Udo Kelter Stand: 30.11.2002 Implementierung relationaler Operationen 15 wir stehen hier wieder vor dem Problem, einen Abschnitt puffern zu müssen. Allerdings sind, wie schon oben erwähnt, Verbundattribute mit geringer Selektivität ohnehin eher unrealistisch. 3-Wege-Verbund. Ein Verbund zwischen drei Relationen r1 1 r2 1 r3 kann im Prinzip auf die Hintereinanderschaltung zweier binärer Verbunde (entweder (r11r2) 1 r3 oder r1 1 (r21r3) ) zurückgeführt werden. Anzustreben ist in diesem Fall ein möglichst kleines Zwischenergebnis. Alternativ kann der 3-stellige Verbund auch direkt, also ohne die ggf. aufwendige Erzeugung eines Zwischenergebnisses, erzeugt werden. Als Grundidee verwenden wir die Verbundberechnung mit Index. Wir durchlaufen die mittlere Relation tupelweise (s. Bild 4) und suchen jeweils “links” (in r1) und “rechts” (in r3) mit Unterstützung je eines Index nach Verbundpartnern. r1 A r2 A B r3 B Abbildung 4: 3-Wege-Verbund Dieses Verfahren ist besonders vorteilhaft anwendbar, wenn r2 eine Verbindungstabelle zwischen r1 und r3 ist. Literatur [RDBM] Kelter, U.: Lehrmodul “Das relationale Datenbankmodell”; 2002 [AVO] Kelter, U.: Lehrmodul “Abfrageverarbeitung und Optimierung”; 2003 c 2002 Udo Kelter Stand: 30.11.2002 Implementierung relationaler Operationen 16 Glossar 3-Wege-Verbund: Verfahren zur Berechnung von zwei Verbunden mit 3 Eingaberelationen einfaches Iterieren: Verfahren zur Verbundberechnung, bei dem die beiden Eingaberelationen in zwei geschachtelten Schleifen durchlaufen werden erweiterbares Hashing: Variante des Hashings, bei dem die Hashtabelle über eine Umsetztabelle indirekt adressiert wird und die einzelnen Felder der Hashtabelle gestreut auf der Platte gespeichert werden können invertierter Datenbestand: Datenbestand, zu dem ein oder mehrere Sekundärindexe vorhanden sind Misch-Verbund (merge join): Verfahren zur Verbundberechnung, bei dem die beiden Eingaberelationen zunächst nach den Verbundattributen sortiert werden und dann für jeden auftretende Wertekombination der Verbundattribute eine “lokaler” Verbund berechnet wird Sekundärindex: Verzeichnis, das zu einzelnen Werten eine Liste von Referenzen auf die Speichereinheiten enthält, in denen dieser Attributwert auftritt Selektivität (eines Attributs einer Relation): Zahl der verschiedenen Werte des Attributs in seiner Relation; der entsprechende Bruchteil der Relation wird im Durchschnitt geliefert, wenn nach einen auftretenden Wert des Attributs selektiert wird c 2002 Udo Kelter Stand: 30.11.2002 Index V(A,r), 9 Verbundberechnung 3-Wege-Verbund, 15, 16 blockorientiertes Iterieren, 12 einfaches Iterieren, 11, 16 Misch-Verbund, 14, 16 mit Index, 13 3-Wege-Verbund, siehe Verbundberechnung Abfrage Intervall-∼, 5, 9 Zwischenergebnis, 11, 15 B*-Baum, 5 Blockadreßtabelle, 6 Blockungsfaktor, 9 Hash-Verfahren, 5 erweiterbares, 6, 16 Index, 5 Indexblock, 5 invertierter Datenbestand, 7, 16 Misch-Verbund, siehe Verbundberechnung nested loop join, 11 Optimierung Projektion, 11 Selektion, 8 Verbundberechnung, 11 von Elementaroperationen, 3 Primärindex, 5 sr , 8 Schlüssel Fremdschlüssel, 13 Suchschlüssel, 7 Sekundärindex, 7, 10, 13, 16 Aktualisierung, 7 Selektivität, 9, 16 17