<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://wiki-de.moshellshocker.dns64.de/index.php?action=history&amp;feed=atom&amp;title=Join-Algorithmus</id>
	<title>Join-Algorithmus - Versionsgeschichte</title>
	<link rel="self" type="application/atom+xml" href="https://wiki-de.moshellshocker.dns64.de/index.php?action=history&amp;feed=atom&amp;title=Join-Algorithmus"/>
	<link rel="alternate" type="text/html" href="https://wiki-de.moshellshocker.dns64.de/index.php?title=Join-Algorithmus&amp;action=history"/>
	<updated>2026-05-30T12:21:10Z</updated>
	<subtitle>Versionsgeschichte dieser Seite in Wikipedia (Deutsch) – Lokale Kopie</subtitle>
	<generator>MediaWiki 1.43.8</generator>
	<entry>
		<id>https://wiki-de.moshellshocker.dns64.de/index.php?title=Join-Algorithmus&amp;diff=1565023&amp;oldid=prev</id>
		<title>imported&gt;Dexxor: /* Nested Loop Join */ Nested Loop leitet hierher weiter</title>
		<link rel="alternate" type="text/html" href="https://wiki-de.moshellshocker.dns64.de/index.php?title=Join-Algorithmus&amp;diff=1565023&amp;oldid=prev"/>
		<updated>2024-08-11T13:25:36Z</updated>

		<summary type="html">&lt;p&gt;&lt;span class=&quot;autocomment&quot;&gt;Nested Loop Join: &lt;/span&gt; &lt;a href=&quot;/index.php/Nested_Loop&quot; class=&quot;mw-redirect&quot; title=&quot;Nested Loop&quot;&gt;Nested Loop&lt;/a&gt; leitet hierher weiter&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Neue Seite&lt;/b&gt;&lt;/p&gt;&lt;div&gt;Ein &amp;#039;&amp;#039;&amp;#039;Join-Algorithmus&amp;#039;&amp;#039;&amp;#039; ist eine Strategie ([[Algorithmus]]) zur [[Implementierung]] von [[Relationale Algebra#Join|Joins]] in [[Relationale Datenbank|relationalen Datenbanken]].&lt;br /&gt;
&lt;br /&gt;
Die optimale Strategie hängt von Größe und Struktur der am Join beteiligten [[Relation (Datenbank)|Relationen]], verwendeten oder verwendbaren [[Datenbankindex|Indizes]], der Größe des [[Arbeitsspeicher|Hauptspeichers]] als auch der Join-Art (Natural Join, θ-Join oder Equi-Join) ab.&lt;br /&gt;
&lt;br /&gt;
== Nested Loop Join ==&lt;br /&gt;
Es werden nacheinander alle [[Tupel (Informatik)|Tupel]] aus der Relation &amp;lt;math&amp;gt;\mathit{R}&amp;lt;/math&amp;gt; ausgewählt und mit jedem Tupel aus der Relation &amp;lt;math&amp;gt;\mathit{S}&amp;lt;/math&amp;gt; verglichen.&lt;br /&gt;
&lt;br /&gt;
Der Algorithmus eignet sich für jeden Join und ist auf mehrere Relationen erweiterbar.&lt;br /&gt;
&lt;br /&gt;
=== Pseudocode ===&lt;br /&gt;
Umsetzung von &amp;lt;math&amp;gt;R \bowtie_{R.a \theta S.b} S&amp;lt;/math&amp;gt; mit &amp;lt;math&amp;gt;\mathit{R}&amp;lt;/math&amp;gt; als &amp;#039;&amp;#039;äußerer&amp;#039;&amp;#039; Relation und &amp;lt;math&amp;gt;\mathit{S}&amp;lt;/math&amp;gt; als &amp;#039;&amp;#039;innerer&amp;#039;&amp;#039; Relation mithilfe zweier geschachtelter [[Schleife (Programmierung)|Schleifen]] (&amp;#039;&amp;#039;{{lang|en|nested loops}}&amp;#039;&amp;#039;) in [[Pseudocode]]:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  foreach r in R do&lt;br /&gt;
    foreach s in S do&lt;br /&gt;
      if r.a θ s.b do&lt;br /&gt;
        ⇒ Ausgabe von (r,s)&lt;br /&gt;
      endif&lt;br /&gt;
    end foreach&lt;br /&gt;
  end foreach&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bewertung ===&lt;br /&gt;
Da alle Tupel im [[Kartesisches Produkt|Kreuzprodukt]] miteinander verknüpft werden, ergibt sich ein Rechenaufwand von &amp;lt;math&amp;gt;\mathcal{O}(|R| \cdot |S|)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Die Anzahl der zu lesenden Blöcke ist im [[Worst Case]] &amp;lt;math&amp;gt;|R| \cdot b_s + b_r&amp;lt;/math&amp;gt;, da für jedes 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]] &amp;lt;math&amp;gt;b_s + b_r&amp;lt;/math&amp;gt; Blöcke gelesen werden.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Varianten ===&lt;br /&gt;
Beim &amp;#039;&amp;#039;&amp;#039;Index Nested Loop Join&amp;#039;&amp;#039;&amp;#039; werden vorhandene oder erstellte Indizes abgeglichen. Die Anzahl der Blockzugriffe hängt dann von Größe und Aufbau der Indexstrukturen ab.&lt;br /&gt;
&lt;br /&gt;
== Block Nested Loop Join ==&lt;br /&gt;
Im Fall, dass beide Relationen &amp;lt;math&amp;gt;\mathit{R}&amp;lt;/math&amp;gt; und &amp;lt;math&amp;gt;\mathit{S}&amp;lt;/math&amp;gt; nicht in den Hauptspeicher passen, verbessert ein blockweiser Vergleich den Nested Loop Join.&lt;br /&gt;
&lt;br /&gt;
Der Algorithmus eignet sich für jeden Join.&lt;br /&gt;
&lt;br /&gt;
=== Pseudocode ===&lt;br /&gt;
Umsetzung von &amp;lt;math&amp;gt;R \bowtie_{R.a \theta S.a} S&amp;lt;/math&amp;gt; in [[Pseudocode]]:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  foreach Block_r in R do&lt;br /&gt;
    foreach Block_s in S do&lt;br /&gt;
      foreach r in Block_r do&lt;br /&gt;
        foreach s in Block_s do&lt;br /&gt;
          if r.a θ s.a do&lt;br /&gt;
            ⇒ Ausgabe von (r,s)&lt;br /&gt;
          endif&lt;br /&gt;
        end foreach&lt;br /&gt;
      end foreach&lt;br /&gt;
    end foreach&lt;br /&gt;
  end foreach&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bewertung ===&lt;br /&gt;
Wie für den Nested Loop Join ist die Komplexität &amp;lt;math&amp;gt;\mathcal{O}(|R| \cdot |S|)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Die Anzahl der zu lesenden Blöcke ist im Worst Case &amp;lt;math&amp;gt;b_r \cdot b_s + b_r&amp;lt;/math&amp;gt;, im Best Case &amp;lt;math&amp;gt;b_s + b_r&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Varianten ===&lt;br /&gt;
Passen beide Relationen nicht in den Hauptspeicher, so werden aus der äußeren Relation jeweils so viele Blöcke wie möglich in den Hauptspeicher geladen. Dies reduziert die Anzahl der Blockzugriffe auf die innere Relation.&lt;br /&gt;
&lt;br /&gt;
== Sort-Merge Join ==&lt;br /&gt;
Beide Relationen werden nach ihren Join-Attributen sortiert. Das Ergebnis kann dann mit einmaligem Scan durch beide sortierte Relationen berechnet werden.&lt;br /&gt;
&lt;br /&gt;
Der Algorithmus eignet sich nur für Natural Join und Equi-Join.&lt;br /&gt;
&lt;br /&gt;
=== Pseudocode ===&lt;br /&gt;
Umsetzung von &amp;lt;math&amp;gt;R \bowtie_{R.a = S.a} S&amp;lt;/math&amp;gt; in [[Pseudocode]]:&lt;br /&gt;
&lt;br /&gt;
  p&amp;lt;sub&amp;gt;r&amp;lt;/sub&amp;gt; := erstes Tupel in R&lt;br /&gt;
  p&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt; := erstes Tupel in S&lt;br /&gt;
  while p&amp;lt;sub&amp;gt;r&amp;lt;/sub&amp;gt; ≠ endof&amp;lt;sub&amp;gt;R&amp;lt;/sub&amp;gt; and p&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt; ≠ endof&amp;lt;sub&amp;gt;S&amp;lt;/sub&amp;gt; do&lt;br /&gt;
    // Sammeln aller Tupel mit gleichen Joinattributen aus S&lt;br /&gt;
    M&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt; := Menge mit Inhalt p&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt;&lt;br /&gt;
    foreach t&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt; in S &amp;gt; p&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt;&lt;br /&gt;
      if t&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt;.a = p&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt;.a&lt;br /&gt;
        M&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt; += Menge mit Inhalt t&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt;&lt;br /&gt;
      elseif&lt;br /&gt;
        p&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt; := t&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt;&lt;br /&gt;
        break foreach&lt;br /&gt;
      endif&lt;br /&gt;
    end foreach&lt;br /&gt;
    // suche passendes Anfangstupel in R&lt;br /&gt;
    foreach t&amp;lt;sub&amp;gt;r&amp;lt;/sub&amp;gt; in R &amp;gt; p&amp;lt;sub&amp;gt;r&amp;lt;/sub&amp;gt;&lt;br /&gt;
      p&amp;lt;sub&amp;gt;r&amp;lt;/sub&amp;gt; = t&amp;lt;sub&amp;gt;r&amp;lt;/sub&amp;gt;&lt;br /&gt;
      if t&amp;lt;sub&amp;gt;r&amp;lt;/sub&amp;gt;.a ≥ t&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt;.a&lt;br /&gt;
        break foreach&lt;br /&gt;
      endif&lt;br /&gt;
    end foreach&lt;br /&gt;
    // Tupel ausgeben&lt;br /&gt;
    foreach t&amp;lt;sub&amp;gt;r&amp;lt;/sub&amp;gt; in R &amp;gt; p&amp;lt;sub&amp;gt;r&amp;lt;/sub&amp;gt;&lt;br /&gt;
      if t&amp;lt;sub&amp;gt;r&amp;lt;/sub&amp;gt;.a &amp;gt; t&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt;.a&lt;br /&gt;
        break foreach&lt;br /&gt;
      endif&lt;br /&gt;
      foreach t&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt; in M&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt;&lt;br /&gt;
        ⇒ Ausgabe von (t&amp;lt;sub&amp;gt;r&amp;lt;/sub&amp;gt;,t&amp;lt;sub&amp;gt;s&amp;lt;/sub&amp;gt;)&lt;br /&gt;
      end foreach&lt;br /&gt;
      p&amp;lt;sub&amp;gt;r&amp;lt;/sub&amp;gt; = t&amp;lt;sub&amp;gt;r&amp;lt;/sub&amp;gt;&lt;br /&gt;
    end foreach&lt;br /&gt;
  end while&lt;br /&gt;
&lt;br /&gt;
=== Bewertung ===&lt;br /&gt;
Die Anzahl der Blockzugriffe für die Sortierung von &amp;lt;math&amp;gt;\mathit{S}&amp;lt;/math&amp;gt; ist im schlechtesten Fall (Worst Case) &amp;lt;math&amp;gt;b_s \cdot \left(2 \cdot \log \left(\frac{b_s}{b_{free}}\right) \right) + b_s&amp;lt;/math&amp;gt;, analog für &amp;lt;math&amp;gt;\mathit{R}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Varianten ===&lt;br /&gt;
Falls Indizes existieren, können diese für das Abrufen der sortierten Join-Attribute verwendet werden. Beim Auslesen der Tupel kann die Zufallsverteilung im Worst Case zu &amp;lt;math&amp;gt;|S| + |R|&amp;lt;/math&amp;gt; Blockzugriffen führen.&lt;br /&gt;
&lt;br /&gt;
Beim &amp;#039;&amp;#039;&amp;#039;Hybrid Merge-Join&amp;#039;&amp;#039;&amp;#039; wird deshalb eine Relation &amp;lt;math&amp;gt;\mathit{S}&amp;lt;/math&amp;gt; sortiert. Danach wird diese über den Index mit den Tupeladressen der anderen Relation &amp;lt;math&amp;gt;\mathit{R}&amp;lt;/math&amp;gt; gemergt. Die Ergebnismenge wird nach den Tupeladressen sortiert und die Tupel aus &amp;lt;math&amp;gt;\mathit{R}&amp;lt;/math&amp;gt; damit mit möglichst wenigen Blockzugriffen dazugelesen.&lt;br /&gt;
&lt;br /&gt;
== Hash-Join (Simple-Hash) ==&lt;br /&gt;
&lt;br /&gt;
Die erste Relation erzeugt mit den Join-Attributen eine Hashtabelle.&lt;br /&gt;
Die Join-Attribute der zweiten Relation werden ebenfalls gehasht. Zeigt der Wert auf ein nicht leeres Bucket in der Hashtabelle, wird das Bucket mit dem aktuellen Tupel verglichen.&lt;br /&gt;
&lt;br /&gt;
Die Hashtabelle wird im Allgemeinen für die kleinere Relation angelegt. Der Hash Join ist nur für Equi-Joins geeignet.&lt;br /&gt;
&lt;br /&gt;
=== Pseudocode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R \bowtie_{R.a = S.b} S&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;#039;&amp;#039;&amp;#039;Für alle&amp;#039;&amp;#039;&amp;#039; Elemente s aus S &amp;#039;&amp;#039;&amp;#039;wiederhole&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
     Hashe über den Join Attributen s(b);&lt;br /&gt;
     Trage Tupel entsprechend den Werten in Hashtabelle ein&lt;br /&gt;
 &amp;#039;&amp;#039;&amp;#039;end&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 &amp;#039;&amp;#039;&amp;#039;Für alle&amp;#039;&amp;#039;&amp;#039; Elemente r aus R &amp;#039;&amp;#039;&amp;#039;wiederhole&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
     Hashe über den Join Attributen r(a);&lt;br /&gt;
     &amp;#039;&amp;#039;&amp;#039;if&amp;#039;&amp;#039;&amp;#039; r auf nicht-leeres Bucket hashed&lt;br /&gt;
         &amp;#039;&amp;#039;&amp;#039;if&amp;#039;&amp;#039;&amp;#039; r &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; s&lt;br /&gt;
             speichere r &amp;lt;math&amp;gt;\bullet&amp;lt;/math&amp;gt; s in Ergebnismenge&lt;br /&gt;
         &amp;#039;&amp;#039;&amp;#039;end&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
     &amp;#039;&amp;#039;&amp;#039;end&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 &amp;#039;&amp;#039;&amp;#039;end&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== Bewertung ===&lt;br /&gt;
&lt;br /&gt;
Die [[Average Case|durchschnittliche Laufzeit]] des Hash-Joins beträgt: &amp;lt;math&amp;gt;\mathcal{O}(n + m)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Varianten ===&lt;br /&gt;
&lt;br /&gt;
==== Hash-Partioned-Join ====&lt;br /&gt;
Die Relationen &amp;lt;math&amp;gt;\mathit{R}&amp;lt;/math&amp;gt; und &amp;lt;math&amp;gt;\mathit{S}&amp;lt;/math&amp;gt; werden mit einer gleich- und zufällig verteilenden [[Hashfunktion]] in &amp;lt;math&amp;gt;n_h&amp;lt;/math&amp;gt; disjunkte Partitionen &amp;lt;math&amp;gt;H_{s_0}&amp;lt;/math&amp;gt; bis &amp;lt;math&amp;gt;H_{s_{n_h}}&amp;lt;/math&amp;gt; (analog für R) zerlegt. Dabei fallen die Tupel der beiden Relationen in die gleichen Buckets, wenn die Wertebereiche ähnlich sind. &lt;br /&gt;
&lt;br /&gt;
Es müssen dadurch nur die Partitionen &amp;lt;math&amp;gt;H_{s_i}&amp;lt;/math&amp;gt; und &amp;lt;math&amp;gt;H_{r_i}&amp;lt;/math&amp;gt; verglichen werden, da sie die Tupel mit den gleichen Join-Attributen enthalten. Der Algorithmus eignet sich nur für Natural Join und Equi-Join.&lt;br /&gt;
&lt;br /&gt;
==== Implementierungen des Hash-Partioned-Join ====&lt;br /&gt;
* [[GRACE Hash Join]]&lt;br /&gt;
* [[Hybrid Hash Join]]&lt;br /&gt;
* [[Hashed Loops Join]]&lt;br /&gt;
&lt;br /&gt;
== Parallel-Join ==&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Auf den einzelnen Prozessoren kann ein beliebiger Join-Algorithmus laufen.&lt;br /&gt;
&lt;br /&gt;
=== Fragment-and-Replicate Join ===&lt;br /&gt;
Eine Erweiterung des Partitioned Join für θ-Joins: die Elemente des Kreuzprodukt der Partitionspaare  &amp;lt;math&amp;gt;H_{r_i}&amp;lt;/math&amp;gt; und &amp;lt;math&amp;gt;H_{s_i}&amp;lt;/math&amp;gt; wird an jeweils einen Prozessor übergeben. Durch die Replikation steigt der Datentransfer stark an.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Datenbanktheorie]]&lt;/div&gt;</summary>
		<author><name>imported&gt;Dexxor</name></author>
	</entry>
</feed>