- Joinalgorithmen
-
Joinalgorithmen sind mögliche Strategien (Algorithmen) zur Implementierung von Joins.
Die optimale Strategie hängt von Größe und Struktur der am Join beteiligten Relationen, verwendeten oder verwendbaren Indizes, der Größe des Hauptspeichers als auch der Join-Art (Natural Join, θ-Join oder Equijoin) ab.
Inhaltsverzeichnis
Nested Loop Join
Es werden nacheinander alle Tupel aus der Relation R ausgewählt und mit jedem Tupel aus der Relation S verglichen.
Der Algorithmus eignet sich für jeden Join und ist auf mehrere Relationen erweiterbar.
Pseudocode
Umsetzung von mit R als äußerer Relation und S als innerer Relation in Pseudocode:
foreach r in R do foreach s in S do if r.a = s.a do ⇒ Ausgabe von (r,s) endif end foreach end foreach
Bewertung
Da alle Tupel im Kreuzprodukt miteinander verknüpft werden, ergibt sich ein Rechenaufwand von .
Die Anzahl der zu lesenden Blöcke ist im worst case , da für jeden Tupel in R alle Blöcke von S erneut geladen werden. Passen beide Relationen in den Speicher, dann müssen für diesen best case bs + br Blöcke gelesen werden. Passt eine der Relationen komplett in den Speicher, so wird sie als innere Relation ausgewählt, ansonsten ist es sinnvoller, die kleinere Relation als äußere Relation zu wählen.
Varianten
Beim Index Nested Loop Join werden vorhandene oder erstellte Indizes abgeglichen. Die Anzahl der Blockzugriffe hängt dann von Größe und Aufbau der Indexstrukturen ab.
Block Nested Loop Join
Im Fall, dass beide Relationen R und S nicht in den Hauptspeicher passen, verbessert ein blockweiser Vergleich den Nested Loop Join.
Der Algorithmus eignet sich für jeden Join.
Pseudocode
Umsetzung von in Pseudocode:
foreach Block<sub>r</sub> in R do foreach Block<sub>s</sub> in S do foreach r in Block<sub>r</sub> do foreach s in Block<sub>s</sub> do if r.a = s.a do ⇒ Ausgabe von (r,s) endif end foreach end foreach end foreach end foreach
Bewertung
Wie für den Nested Loop Join ist die Komplexität .
Die Anzahl der zu lesenden Blöcke ist im worst case , im best case bs + br.
Varianten
Passen beide Relationen nicht in den Hauptspeicher, so werden aus der äußere Relation jeweils so viele Blöcke wie möglich in den Hauptspeicher geladen. Das reduziert die Anzahl der Blockzugriffe auf die innere Relation.
Sort-Merge Join
Beide Relationen werden nach ihren Join-Attributen sortiert. Das Ergebnis kann dann mit einmaligem Scan durch beide sortierte Relationen berechnet werden.
Der Algorithmus eignet sich nur für Natural Join und Equijoin.
Pseudocode
Umsetzung von in Pseudocode:
pr := erstes Tupel in R ps := erstes Tupel in S while pr ≠ endofR and ps ≠ endofS do // Sammeln aller Tupel mit gleichen Joinattributen aus S Ms := Menge mit Inhalt ps foreach ts in S > ps if ts.a = ps.a Ms += Menge mit Inhalt ts elseif ps := ts break foreach endif end foreach // suche passendes Anfangstupel in R foreach tr in R > pr pr = tr if tr.a ≥ ts.a break foreach endif end foreach // Tupel ausgeben foreach tr in R > pr if tr.a > ts.a break foreach endif foreach ts in Ms ⇒ Ausgabe von (tr,ts) end foreach pr = tr end foreach end while
Bewertung
Eine Sortierung kann mit dem Aufwand von durchgeführt werden. Die Anzahl der Blockzugriffe für die Sortierung von S ist im worst case , analog für R.
Ein Merge der beiden Relationen kostet nach der Sortierung , Im besten Fall (best case), das heißt die Relationen sind bereits sortiert, sind die Kosten für den Merge die einzigen.
Varianten
Falls Indizes existieren, können diese für das Abrufen der sortierten Joinattribute verwendet werden. Beim Auslesen der Tupel kann die Zufallsverteilung im worst case zu | S | + | R | Blockzugriffen führen.
Beim Hybrid Merge-Join wird deshalb eine Relation S sortiert. Danach wird diese über den Index mit den Tupeladressen der anderen Relation R gemergt. Die Ergebnismenge wird nach den Tupeladressen sortiert und die Tupel aus R damit mit möglichst wenigen Blockzugriffen dazugelesen.
Hash-Join (Simple-Hash)
Die erste Relation erzeugt mit den Join-Attributen eine Hashtabelle. Die Join-Attribute der zweiten Relation werden ebenfalls gehashed. Zeigt der Wert auf ein nicht leeres Bucket in der Hashtabelle, wird das Bucket mit dem aktuellen Tupel verglichen.
Die Hashtabelle wird im Allgemeinen für die kleinere Relation angelegt. Der Hash Join ist nur für Join-Operationen mit dem Gleichheitszeichen geeignet.
Pseudocode
Für alle Elemente s aus S wiederhole Hashe über den Join Attributen s(b); Trage Tupel entsprechend der Werte in Hashtabelle ein end Für alle Elemente r aus R wiederhole Hashe über den Join Attributen r(a); if r auf nicht-leeres Bucket hashed if r θ s speichere r s in Ergebnismenge end end end
Bewertung
Im Allgemeinen gilt:
Varianten
Hash-Partioned-Join
Die Relationen R und S werden mit einer gleich- und zufällig verteilenden Hashfunktion in nh disjunkte Partitionen bis (analog für R) zerlegt. Dabei fallen die Tupel der beiden Relationen in die gleichen Buckets wenn die Wertebereiche ähnlich sind.
Es müssen dadurch nur die Partitionen und verglichen werden, da sie die Tupel mit den gleichen Joinattributen enthalten. Der Algorithmus eignet sich nur für Natural Join und Equijoin.
Implementierungen des Hash-Partioned-Join
- GRACE Hash Join
- Hybrid Hash Join
- Hashed Loops Join
Parallel-Join
Parallelisierte Algorithmen verteilen die Arbeit an einem Join auf mehrere Prozessoren oder Rechner. Sie werden in Paralleldatenbanken oder in arbeitsverteilenden Frameworks wie MapReduce, Dryad und Hadoop angewandt.
Auf den einzelnen Prozessoren kann ein beliebiger Join-Algorithmus laufen.
Fragment-and-Replicate Join
Eine Erweiterung des Partitioned Join für θ-Joins: die Elemente des Kreuzprodukt der Partitionspaare und wird an jeweils einen Prozessor übergeben. Durch die Replikation steigt der Datentransfer stark an.
Beim asymmetrischen Fragment-and-Replicate Join jeweils eine Partition aus R und die gesamte Relation S an einen Prozessor übergeben.
Kategorie:- Datenbanktheorie
Wikimedia Foundation.