web-dev-qa-db-de.com

Hive - Effizientes Zusammenfügen von zwei Tabellen

Ich verbinde zwei große Tabellen in Hive (eine ist mehr als 1 Milliarde Zeilen, eine ist ungefähr 100 Millionen Zeilen):

create table joinedTable as select t1.id, ... from t1 join t2 ON (t1.id = t2.id);

Ich habe die beiden Tabellen auf dieselbe Art und Weise in Buckets zusammengefasst, indem ich sie nach ID in jeweils 100 Buckets gruppiere, aber die Abfrage dauert immer noch sehr lange. 

Irgendwelche Vorschläge, wie man das beschleunigen kann? 

13
maia

Wenn Sie die Daten mit den Join-Schlüsseln abgelegt haben, können Sie den Bucket-Map-Join verwenden. Dazu muss die Anzahl der Buckets in einer Tabelle ein Vielfaches der Menge der Buckets in der anderen Tabelle sein. Es kann durch Ausführen von set Hive.optimize.bucketmapjoin=true; vor der Abfrage aktiviert werden. Wenn die Tabellen die Bedingungen nicht erfüllen, führt Hive einfach den normalen Inner Join aus.

Wenn beide Tabellen über die gleiche Anzahl von Buckets verfügen und die Daten nach den Bucket-Schlüsseln sortiert werden, kann Hive den schnelleren Sort-Merge-Join durchführen. Um es zu aktivieren, müssen Sie die folgenden Befehle ausführen:

set Hive.input.format=org.Apache.hadoop.Hive.ql.io.BucketizedHiveInputFormat;
set Hive.optimize.bucketmapjoin=true;
set Hive.optimize.bucketmapjoin.sortedmerge=true;

Einige Visualisierungen der verschiedenen Verbindungstechniken finden Sie unter https://cwiki.Apache.org/confluence/download/attachments/27362054/Hive+Summit+2011-join.pdf .

15
Adrian Lange

Aus meiner Sicht ist die Antwort etwas komplizierter als das, was @Adrian Lange angeboten hat. 

Zuerst müssen Sie einen sehr wichtigen Unterschied zwischen BucketJoin und Sort-Merge Bucket Join (SMBJ) verstehen: 

Um ein bucketjoin auszuführen, muss "die Anzahl der Buckets in einer Tabelle ein Vielfaches der Menge der Buckets in der anderen Tabelle sein", wie zuvor angegeben, und außerdem muss Hive.optimize.bucketmapjoin auf "true" gesetzt sein.
Bei der Ausgabe eines Joins wandelt Hive ihn in ein Bucketjoin um, wenn die oben genannten Bedingungen ABER auftreten, und darauf achten, dass Hive das Bucketing nicht erzwingt! Dies bedeutet, dass das Erstellen der Tabelle mit Buckets nicht ausreicht, um die Tabelle tatsächlich in die angegebene Anzahl von Buckets zu setzen, da Hive dies nicht erzwingt, es sei denn, Hive.enforce.bucketing ist auf true gesetzt (was bedeutet, dass die Anzahl der Buckets tatsächlich von festgelegt wird) Anzahl der Reduzierer in der Endphase der Abfrage (Einfügen von Daten in die Tabelle).
Wie bei der Leistung, beachten Sie bitte, dass bei Verwendung eines Bucketjoin a Einzelaufgabe die "kleinere" Tabelle in den verteilten Cache gelesen wird, bevor die Mapper darauf zugreifen und dies tun Der Join - Diese Phase wäre wahrscheinlich sehr lang und ineffektiv, wenn Ihre Tabelle ~ 100m Zeilen hat!
Nach den Stationen wird der Join genauso durchgeführt wie bei einem regulären Join in den Reduzierern.

Um ein SMBJ ausführen zu können, müssen beide Tabellen die gleiche Anzahl von Buckets in denselben Spalten haben und nach diesen Spalten sortiert werden, zusätzlich dazu, Hive.optimize.bucketmapjoin.sortedmerge auf true zu setzen.
Wie bei der vorherigen Optimierung erzwingt Hive nicht das Bucketing und die Sortierung. Es wird vielmehr davon ausgegangen, dass Sie sichergestellt haben, dass die Tabellen tatsächlich abgelegt und sortiert wurden (nicht nur per Definition, sondern durch Setzen von Hive.enforce.sorting oder manuelles Sortieren der Daten Einfügen) - Dies ist sehr wichtig, da es in beiden Fällen kann zu falschen Ergebnissen führen.
Diese Optimierung ist aus Performancegründen aus folgenden Gründen wesentlich effizienter:

  1. Jeder Mapper liest beide Buckets, und es gibt keinen Konflikt mit einer einzelnen Task für das Laden von verteiltem Cache
  2. Der durchgeführte Join ist ein Merge-Sort-Join, da die Daten bereits sortiert sind, was sehr effizient ist. 

Bitte beachten Sie folgende Überlegungen:

  • in beiden Fällen set Hive.input.format=org.Apache.hadoop.Hive.ql.io.BucketizedHiveInputFormat;
    sollte ausgeführt werden
  • in beiden Fällen sollte eine /*+ MAPJOIN(b) */ in der Abfrage angewendet werden (direkt nach der select und wobei b die kleinere Tabelle ist).
  • Wie viele Eimer?
    Dies sollte aus diesem Blickwinkel betrachtet werden: Die Betrachtung sollte strikt auf die größere Tabelle angewendet werden, da sie mehr Einfluss aus dieser Richtung hat. Letztere wird die Konfiguration auf die kleinere Tabelle als ein Muss anwenden. Als Faustregel gilt, dass jeder Eimer zwischen 1 und 3 Blöcke enthalten sollte, wahrscheinlich in der Nähe von 2 Blöcken. Wenn Ihre Blockgröße also 256 MB beträgt, erscheint es mir vernünftig, ~ 512 MB Daten in jedem Bucket in der größeren Tabelle zu haben, so dass dies zu einem einfachen Divisionsproblem wird.

Vergessen Sie auch nicht, dass diese Optimierungen alleine nicht immer eine schnellere Abfragezeit garantieren.
Nehmen wir an, Sie entscheiden sich für eine SMBJ. Dadurch werden die Kosten für das Sortieren von 2 Tabellen vor dem Ausführen des Joins erhöht. Je öfter Sie Ihre Abfrage ausführen, desto weniger zahlen Sie für diese Sortierphase. 

Manchmal führt ein einfacher Join zur besten Leistung, und keine der oben genannten Optimierungen hilft, und Sie müssen den regulären Join-Vorgang entweder auf Anwendungsebene oder auf logischer Ebene optimieren, oder indem Sie die MapReduce/Hive-Einstellungen wie Speicherbelegung/Parallelität usw. anpassen.

15
dimamah

Ich glaube nicht, dass es ein Muss-Kriterium ist "die Anzahl der Buckets in einer Tabelle muss ein Vielfaches der Anzahl der Buckets in der anderen Tabelle sein" für den Map-Bucket-Join. Wir können auch die gleiche Anzahl von Buckets verwenden.

0
user3340714