JOIN создает новую таблицу, объединяя столбцы одной или нескольких таблиц на основе общих значений. Это распространенная операция в базах данных с поддержкой SQL, соответствующая операции JOIN в реляционной алгебре. Частный случай, когда таблица соединяется сама с собой, часто называют “self-join”.
Синтаксис
ON и столбцы из предложения USING называются “ключами JOIN”. Если не указано иное, JOIN создаёт декартово произведение строк с совпадающими “ключами JOIN”, из-за чего в результате может оказаться гораздо больше строк, чем в исходных таблицах.
Поддерживаемые типы JOIN
| Тип | Описание |
|---|---|
INNER JOIN | возвращаются только совпадающие строки. |
LEFT OUTER JOIN | помимо совпадающих строк возвращаются несовпадающие строки из левой таблицы. |
RIGHT OUTER JOIN | помимо совпадающих строк возвращаются несовпадающие строки из правой таблицы. |
FULL OUTER JOIN | помимо совпадающих строк возвращаются несовпадающие строки из обеих таблиц. |
CROSS JOIN | создает декартово произведение всех строк таблиц; “ключи JOIN” не указываются. |
NATURAL JOIN | автоматически выполняет JOIN по всем столбцам с одинаковыми именами в обеих таблицах; каждый общий столбец появляется в результате только один раз. Поддерживает варианты INNER (по умолчанию), LEFT, RIGHT и FULL. Эквивалентен JOIN ... USING (col1, col2, ...), где список столбцов определяется автоматически. |
JOINбез указания типа подразумеваетINNER.- Ключевое слово
OUTERможно без опасений опустить. - Альтернативный синтаксис для
CROSS JOIN— указать несколько таблиц вFROMclause, разделив их запятыми. - Если у
NATURAL JOINнет совпадающих столбцов, он работает какCROSS JOIN.
| Тип | Описание |
|---|---|
LEFT SEMI JOIN, RIGHT SEMI JOIN | Разрешающий список по “ключам JOIN” без построения декартова произведения. |
LEFT ANTI JOIN, RIGHT ANTI JOIN | Запрещающий список по “ключам JOIN” без построения декартова произведения. |
LEFT ANY JOIN, RIGHT ANY JOIN, INNER ANY JOIN | Частично (для противоположной стороны LEFT и RIGHT) или полностью (для INNER и FULL) отключает декартово произведение для стандартных типов JOIN. |
ASOF JOIN, LEFT ASOF JOIN | Объединение последовательностей с неточным совпадением. Использование ASOF JOIN описано ниже. |
PASTE JOIN | Выполняет горизонтальную конкатенацию двух таблиц. |
Если для join_algorithm задано значение
partial_merge, то RIGHT JOIN и FULL JOIN поддерживаются только со strictness ALL (SEMI, ANTI, ANY и ASOF не поддерживаются).Настройки
join_default_strictness.
Поведение сервера ClickHouse для операций ANY JOIN зависит от настройки any_join_distinct_right_table_keys.
См. также
join_algorithmjoin_any_take_last_rowjoin_use_nullspartial_merge_join_rows_in_right_blocksjoin_on_disk_max_files_to_mergeany_join_distinct_right_table_keys
cross_to_inner_join_rewrite, чтобы задать поведение, если ClickHouse не удаётся преобразовать CROSS JOIN в INNER JOIN. Значение по умолчанию — 1, что позволяет продолжить выполнение JOIN, но он будет медленнее. Установите cross_to_inner_join_rewrite в 0, если хотите, чтобы было сгенерировано исключение, и в 2, чтобы не выполнять cross joins, а вместо этого принудительно преобразовывать все joins через запятую и cross joins. Если преобразование не удастся при значении 2, вы получите сообщение об ошибке: “Please, try to simplify WHERE section”.
Условия в разделе ON
ON может содержать несколько условий, объединённых с помощью операторов AND и OR. Условия, задающие ключи JOIN, должны:
- ссылаться как на левую, так и на правую таблицу
- использовать оператор равенства
JOIN. Обратите внимание: если поместить те же условия в раздел WHERE и они не выполняются, то строки всегда отфильтровываются из результата.
Оператор OR в условии ON работает на основе алгоритма hash join — для каждого аргумента OR, содержащего ключи JOIN, создаётся отдельная хеш-таблица, поэтому расход памяти и время выполнения запроса растут линейно по мере увеличения числа выражений OR в условии ON.
Если условие ссылается на столбцы из разных таблиц, то на данный момент поддерживается только оператор равенства (
=).table_1 и table_2:
table_2:
Query
C и пустым текстовым столбцом. Она включена в результат, поскольку используется JOIN типа OUTER.
Response
INNER и несколькими условиями:
Query
Response
INNER и условием с OR:
Query
Response
INNER и условиями с OR и AND:
По умолчанию поддерживаются условия неравенства, если в них используются столбцы из одной и той же таблицы.
Например,
t1.a = t2.key AND t1.b > 0 AND t2.b > t2.c, поскольку в t1.b > 0 используются только столбцы из t1, а в t2.b > t2.c — только столбцы из t2.
Однако вы можете попробовать экспериментальную поддержку условий вида t1.a = t2.key AND t1.b > t2.key; подробнее см. в разделе ниже.Query
Response
JOIN с условиями неравенства для столбцов из разных таблиц
ALL/ANY/SEMI/ANTI INNER/LEFT/RIGHT/FULL JOIN не только с условиями равенства, но и с условиями неравенства. Условия неравенства поддерживаются только для алгоритмов JOIN hash и grace_hash. Условия неравенства не поддерживаются при использовании join_use_nulls.
Пример
Таблица t1:
t2
Значения NULL в ключах JOIN
NULL не равно никакому значению, включая само себя. Это означает, что если ключ JOIN в одной таблице имеет значение NULL, он не будет сопоставлен со значением NULL в другой таблице.
Пример
Таблица A:
B:
Charlie из таблицы A и строка с оценкой 88 из таблицы B отсутствуют в результате из-за значения NULL в ключе JOIN.
Если вы хотите сопоставлять значения NULL, используйте функцию isNotDistinctFrom для сравнения ключей JOIN.
Использование ASOF JOIN
ASOF JOIN полезен, когда нужно соединить записи без точного совпадения.
Для этого алгоритма JOIN в таблицах требуется специальный столбец. Этот столбец:
- должен содержать упорядоченную последовательность;
- может иметь один из следующих типов: Int, UInt, Float, Date, DateTime, Decimal;
- для алгоритма
hashJOIN он не может быть единственным столбцом в условииJOIN.
ASOF JOIN ... ON:
SELECT count() FROM table_1 ASOF LEFT JOIN table_2 ON table_1.a == table_2.b AND table_2.t <= table_1.t.
Для поиска ближайшего соответствия поддерживаются следующие условия: >, >=, <, <=.
Синтаксис ASOF JOIN ... USING:
ASOF JOIN использует equi_columnX для JOIN по равенству и asof_column для JOIN по ближайшему совпадению с условием table_1.asof_column >= table_2.asof_column. Столбец asof_column всегда указывается последним в секции USING.
Например, рассмотрим следующие таблицы:
ASOF JOIN может брать временную метку пользовательского события из table_1 и находить событие в table_2, временная метка которого наиболее близка к временной метке события из table_1 в соответствии с условием ближайшего совпадения. Если доступны равные значения временной метки, именно они считаются ближайшими. Здесь столбец user_id можно использовать для JOIN по равенству, а столбец ev_time — для JOIN по ближайшему совпадению. В нашем примере event_1_1 можно соединить с event_2_1, а event_1_2 — с event_2_3, но event_2_2 соединить нельзя.
ASOF JOIN поддерживается только алгоритмами JOIN hash и full_sorting_merge.
Он не поддерживается в движке таблицы Join.Использование PASTE JOIN
PASTE JOIN является таблица, содержащая все столбцы левого подзапроса, а затем все столбцы правого подзапроса.
Строки сопоставляются по их позициям в исходных таблицах (порядок строк должен быть определён).
Если подзапросы возвращают разное количество строк, лишние строки будут отброшены.
Пример:
Распределенный JOIN
- При использовании обычного
JOINзапрос отправляется на удаленные серверы. Подзапросы выполняются на каждом из них, чтобы сформировать правую таблицу, после чего выполняется JOIN с этой таблицей. Иными словами, правая таблица формируется отдельно на каждом сервере. - При использовании
GLOBAL ... JOINсервер-инициатор сначала выполняет подзапрос, чтобы вычислить одну из сторон JOIN, и собирает результат во временную таблицу. Затем эта временная таблица передается на каждый удаленный сервер, и на них выполняются запросы с использованием переданных временных данных. ДляLEFTиINNERJOIN правая таблица вычисляется подзапросом. ДляRIGHTJOIN вместо этого вычисляется левая таблица, поскольку сохраняется правая таблица, и ее следует читать из сегментов.
GLOBAL. Дополнительные сведения см. в разделе Распределенные подзапросы.
Неявное преобразование типов
INNER JOIN, LEFT JOIN, RIGHT JOIN и FULL JOIN поддерживают неявное преобразование типов для “ключей JOIN”. Однако запрос не может быть выполнен, если ключи JOIN из левой и правой таблиц нельзя привести к одному типу (например, не существует типа данных, который мог бы хранить все значения и из UInt64, и из Int64, или из String и Int32).
Пример
Рассмотрим таблицу t_1:
t_2:
Рекомендации по использованию
Обработка пустых ячеек или ячеек со значением NULL
JOIN — это поля Nullable, то строки, в которых хотя бы один из ключей имеет значение NULL, не объединяются.
Синтаксис
USING, должны иметь одинаковые имена в обоих подзапросах, а остальные столбцы должны называться по-разному. Чтобы изменить имена столбцов в подзапросах, можно использовать псевдонимы.
Предложение USING задаёт один или несколько столбцов для JOIN, тем самым устанавливая равенство этих столбцов. Список столбцов указывается без скобок. Более сложные условия JOIN не поддерживаются.
Ограничения синтаксиса
JOIN в одном запросе SELECT:
- Получение всех столбцов через
*доступно, только если объединяются таблицы, а не подзапросы. - Секция
PREWHEREнедоступна. - Предложение
USINGнедоступно.
ON, WHERE и GROUP BY:
- Произвольные выражения нельзя использовать в секциях
ON,WHEREиGROUP BY, но можно определить выражение в секцииSELECT, а затем использовать его в этих секциях через алиас.
Производительность
JOIN порядок выполнения по отношению к другим этапам запроса не оптимизируется. JOIN (поиск в правой таблице) выполняется до фильтрации в WHERE и до агрегации.
Каждый раз, когда выполняется запрос с одним и тем же JOIN, подзапрос запускается заново, потому что результат не кэшируется. Чтобы этого избежать, используйте специальный движок таблицы Join — подготовленный массив для JOIN, который всегда находится в оперативной памяти.
В некоторых случаях эффективнее использовать IN вместо JOIN.
Если JOIN нужен для соединения с таблицами измерений (это относительно небольшие таблицы, содержащие свойства измерений, например названия рекламных кампаний), он может быть не очень удобен, поскольку к правой таблице приходится обращаться заново при каждом запросе. В таких случаях вместо JOIN следует использовать возможность «словари». Подробнее см. в разделе Словари.
Ограничения памяти
right_table и создает для нее хеш-таблицу в оперативной памяти. Если включен параметр join_algorithm = 'auto', то после достижения определенного порога потребления памяти ClickHouse переключается на алгоритм merge JOIN. Описание алгоритмов JOIN см. в настройке join_algorithm.
Если вам нужно ограничить потребление памяти операцией JOIN, используйте следующие настройки:
- max_rows_in_join — Ограничивает количество строк в хеш-таблице.
- max_bytes_in_join — Ограничивает размер хеш-таблицы.
Примеры
- Блог: ClickHouse: молниеносно быстрая СУБД с полной поддержкой SQL JOIN — Часть 1
- Блог: ClickHouse: молниеносно быстрая СУБД с полной поддержкой SQL JOIN — Внутреннее устройство — Часть 2
- Блог: ClickHouse: молниеносно быстрая СУБД с полной поддержкой SQL JOIN — Внутреннее устройство — Часть 3
- Блог: ClickHouse: молниеносно быстрая СУБД с полной поддержкой SQL JOIN — Внутреннее устройство — Часть 4