Особенности JOIN

В интерфейсе создания датасета можно объединять данные, перетаскивая таблицы на рабочую область и настраивая связи между ними через оператор JOIN. Для таблиц YTsaurus такое объединение вызывает ошибку. Ошибка возникает из-за структуры хранения таблиц и схемы выполнения запросов в YTsaurus по умолчанию.

Хранение табличных данных

Схема хранения таблиц в YTsaurus принципиально отличается от таковой в ClickHouse:

  • В YTsaurus базовый примитив хранения данных — статическая таблица, строки которой лежат по чанкам, произвольным образом распределенным по кластеру. По умолчанию данные распределяются по шардам согласно некоторому ключу шардирования. Статические таблицы крайне неэффективны в задачах, которые требуют точечного чтения данных.

    Примечание

    В ClickHouse шардирование обеспечивает локальность строк с одним значением выражения шардирования на одной машине.

  • В YTsaurus поддерживается понятие сортированной таблицы — в схеме таблицы может учитываться, что ее строки сортированы по некоторому префиксу колонок. Такие колонки называются ключевыми. Это более эффективный примитив хранения данных — динамическая таблица.

    Примечание

    В YTsaurus сортировка обеспечивает локальность строк с одним значением ключа в одном чанке (либо в наборе подряд идущих).

Простой SELECT-запрос в CHYT

SELECT-запрос, не содержащий оператора JOIN, по своей сути является потоковым. В нем происходит чтение данных из единственного источника и последующая обработка строк. Возможно применение к полям функций и агрегаций.

В CHYT такой запрос реализован следующим образом:

  1. На некоторый инстанс клики поступает такой запрос. Данный инстанс называется координатором запроса, так как он определяет дальнейший план выполнения.
  2. Координатор отправляет в каждый инстанс по внутреннему tcp-протоколу переписанный запрос. В этом запросе вместо названия входной таблицы подставлена закодированная последовательность chunk slice, где chunk slice это некоторый диапазон внутри одного чанка. (Диапазон задается граничными номерами строк или ключами.)
  3. Каждый инстанс исполняет переписанный запрос, и возвращает координатору результат исполнения, тот производит финальную агрегацию (если нужно) и уже отвечает пользователю.

Виды запросов с JOIN в ClickHouse

Как и в случае с простым запросом, SELECT-запрос с использованием оператора JOIN поступает на инстанс клики, который называется координатором запроса. Координатор запроса определяет дальнейший план выполнения, а распределение нагрузки между инстансами определяется вариантом исполнения конструкции lhs JOIN rhs USING/ON:

  • Distributed local JOIN выполняется в ClickHouse по умолчанию. Если таблицы шардированы одинаковым образом, то совпадающая пара ключей не может оказаться на разных машинах. Таким образом, lhs и rhs на каждом инстансе интерпретируются как соответствующие им локальные таблицы. При этом разбитый координатором на части запрос можно исполнять независимо на каждом инстансе.

    Примечание

    Метод требует использование одинаковой схемы шардирования на таблицах.

  • GLOBAL JOIN выполняется, если использовать ключевое слово GLOBAL рядом с JOIN. На координаторе запроса полностью исполняется и материализуется правый аргумент rhs. Затем его сериализованное представление рассылается вместе с запросом по инстансам. Инстансы используют это представление для получения правой части в своей памяти.

    Примечание

    • Данный метод эффективен, когда rhs сравнительно небольшого размера, а инстансов сравнительно немного. Иначе может возникнуть нехватка ресурсов при выполнении rhs на координаторе, или при раздаче координатором по сети сериализованного представления с подзапросом.
    • Метод не требует никаких дополнительных условий на согласованность схемы хранения/шардирования на таблицах.
  • JOIN via subqueries. ClickHouse позволяет заключить lhs и/или rhs в скобки, и это существенно влияет на план исполнения:

    1. На координаторе независимо исполняется левая часть.
    2. Независимо исполняется правая часть.
    3. Правая часть помещается в оперативную память в хеш-таблицу.
    4. Происходит полное исполнение JOIN только на координаторе.
    1. На координаторе независимо исполняется левая часть, как если бы запрос выглядел просто как SELECT lhs.

    2. Координатор отправляет на инстансы свои запросы, оставив JOIN (rhs) как есть.

    3. Каждый инстанс исполняет rhs независимо.

      Примечание

      Это может привести к кратно большей нагрузке, так как каждый инстанс будет материализовывать правую часть независимо. Поэтому защитный механизм в ClickHouse по умолчанию запрещает такое поведение и приводит к ошибке Double-distributed IN/JOIN subqueries is denied.

Особенность запросов с JOIN в CHYT

При выполнении SELECT-запроса с использованием оператора JOIN в CHYT по умолчанию действует логика Sorted JOIN. Она основана на одинаковой схеме сортировки колонок. Используется обычная конструкция lhs JOIN rhs USING/ON.

При этом на lhs и rhs налагаются дополнительные ограничения:

  • Части lhs и rhs должны быть сортированными таблицами.
  • В условии USING/ON должны использоваться только отсортированные колонки.

Например:

  • Пусть lhs отсортирована по колонкам l1, l2, ..., ln , а rhs — по колонкам r1, r2, ..., rm.
  • Условие JOIN ON должно выглядеть как набор равенств l1 = r1 , ..., lk = rk для некоторого k (сами равенства могут идти в произвольном порядке).
  • Это может быть выражено как набором равенств в условии ON, так и набором общих ключевых колонок в конструкции USING, но не набором равенств в условии WHERE.

При соблюдении этих условий координатор запроса формирует пары соответствующих диапазонов из lhs и rhs и распределяет их по инстансам в подзапросах.

Если же это условие не выполнено, выходит ошибка. В этом случае следует либо использовать GLOBAL JOIN, либо заключать правую часть (rhs) в подзапрос.