Улей - эффективное соединение двух таблиц

Я присоединяюсь к двум большим таблицам в Hive (один - более 1 миллиарда строк, один - около 100 миллионов строк):

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

Я разделил две таблицы таким же образом, кластеризацию по id на 100 кодеров для каждого, но запрос все еще занимает много времени.

Любые предложения о том, как ускорить это?

Ответ 1

По мере того, как вы сворачивали данные с помощью ключей соединения, вы могли бы использовать объединение ведомых карт. Для этого количество ведер в одной таблице должно быть кратным количеству ведер в другой таблице. Его можно активировать, выполнив set hive.optimize.bucketmapjoin=true; перед запросом. Если таблицы не соответствуют условиям, Hive будет просто выполнять обычную Inner Join.

Если обе таблицы имеют одинаковое количество ковшей, а данные сортируются с помощью клавиш ведра, Hive может выполнять более быструю сортировку слияния. Чтобы активировать его, вы должны выполнить следующие команды:

set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
set hive.optimize.bucketmapjoin=true;
set hive.optimize.bucketmapjoin.sortedmerge=true;

Вы можете найти некоторые визуализации различных методов соединения в https://cwiki.apache.org/confluence/download/attachments/27362054/Hive+Summit+2011-join.pdf.

Ответ 2

Как я вижу, ответ немного сложнее, чем предлагал @Adrian Lange.

Сначала вы должны понять очень важное различие между BucketJoin и Sort-Merge Bucket Join (SMBJ):

Для выполнения bucketjoin количество ведер в одной таблице должно быть кратно количеству ведер в другой таблице ", как указано выше, и, кроме того, hive.optimize.bucketmapjoin должно быть установлено в true.
Выдавая соединение, куст преобразует его в bucketjoin, если указанное выше условие имеет место НО, обратите внимание, что улей не будет использовать bucketing! это означает, что создание таблицы в таблице недостаточно для того, чтобы таблица фактически была размещена в указанном количестве ведер, поскольку улей не применяет это, если для параметра hive.enforce.bucketing не установлено значение true (это означает, что на самом деле установлено количество ведер на количество редукторов на заключительном этапе запроса, вставляя данные в таблицу).
Обратите внимание, что при использовании bucketjoin одиночной задачи читается "меньшая" таблица в распределенный кеш, прежде чем получатели получат доступ к нему и сделают соединение - Этот этап, вероятно, будет очень длинным и неэффективным, если в вашей таблице будет ~ 100 м строк!
После подопечных соединение будет выполнено так же, как при регулярном соединении, выполняемом в редукторах.

Для выполнения SMBJ обе таблицы должны иметь одинаковое количество ведер, в тех же столбцах и сортироваться по этим столбцам в дополнение к установке hive.optimize.bucketmapjoin.sortedmerge в true.
Как и в предыдущей оптимизации, Hive не применяет bucketing и сортировку, но предполагает, что вы убедитесь, что таблицы фактически размещены и отсортированы (не только по определению, но и при установке hive.enforce.sorting или вручную сортировке данных при их вставке) - Это очень важно, поскольку может привести к неправильным результатам в обоих случаях.
С точки зрения эффективности эта оптимизация более эффективна по следующим причинам:

  • Каждый преобразователь считывает оба ведра и не существует единого конфликта задач для загрузки распределенного кэша.
  • Выполнение соединения - это объединение сортировки слиянием, поскольку данные уже отсортированы, что является более эффективным.

Обратите внимание на следующие соображения:

  • в обоих случаях set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
    должен быть выполнен
  • в обоих случаях a /*+ MAPJOIN(b) */ следует применять в запросе (сразу после select и где b - меньшая таблица)
  • Сколько ведер?
    Это следует рассматривать под этим углом: рассмотрение должно строго применяться к более крупной таблице, поскольку оно имеет большее влияние в этом направлении, и последнее конфигурация будет применяться к меньшей таблице в качестве обязательного. Я думаю, что, как правило, каждый ведро должен содержать от 1 до 3 блоков, вероятно, около двух блоков. поэтому, если размер вашего блока составляет 256 Мбайт, это разумно для меня, чтобы иметь ~ 512 МБ данных в каждом ковше в большой таблице, чтобы это стало простой проблемой с разделением.

Кроме того, не забывайте, что эти оптимизации не всегда гарантируют более быстрое время запроса.
Допустим, вы решили сделать SMBJ, это добавляет стоимость сортировки 2 таблиц до запуска соединения - поэтому чем больше раз вы будете запускать свой запрос, тем меньше вы платите за этот этап сортировки.

Иногда простое соединение приведет к максимальной производительности, и ни одна из вышеперечисленных оптимизаций не поможет, и вам придется оптимизировать процесс обычного соединения либо на уровне приложения/логики, либо путем настройки параметров MapReduce/Hive, таких как использование памяти / parallelism и т.д.

Ответ 3

Я не думаю, что его критерии должны быть "количество ведер в одной таблице должно быть кратным количеству ведер в другой таблице" для объединения bucket map. Мы можем иметь одинаковое количество ковшей.