JOIN клаузула
JOIN создает новую таблицу, комбинируя столбцы из одной или нескольких таблиц, используя значения, общие для каждой из них. Это распространенная операция в базах данных с поддержкой SQL, которая соответствует объединению в реляционной алгебре. Специальный случай объединения одной таблицы часто называют "самообъединением".
Синтаксис
Выражения из клаузулы ON
и столбцы из клаузулы USING
называются "ключами объединения". Если не указано иное, JOIN создает декартово произведение из строк с совпадающими "ключами объединения", что может привести к гораздо большему количеству строк в результате, чем в исходных таблицах.
Связанный контент
- Блог: ClickHouse: Долговременная Быстрая СУБД с Полной Поддержкой SQL Join - Часть 1
- Блог: ClickHouse: Долговременная Быстрая СУБД с Полной Поддержкой SQL Join - За Кулисами - Часть 2
- Блог: ClickHouse: Долговременная Быстрая СУБД с Полной Поддержкой SQL Join - За Кулисами - Часть 3
- Блог: ClickHouse: Долговременная Быстрая СУБД с Полной Поддержкой SQL Join - За Кулисами - Часть 4
Поддерживаемые типы JOIN
Поддерживаются все стандартные типы SQL JOIN:
INNER JOIN
, возвращаются только совпадающие строки.LEFT OUTER JOIN
, возвращаются несовпадающие строки из левой таблицы в дополнение к совпадающим строкам.RIGHT OUTER JOIN
, возвращаются несовпадающие строки из правой таблицы в дополнение к совпадающим строкам.FULL OUTER JOIN
, возвращаются несовпадающие строки из обеих таблиц в дополнение к совпадающим строкам.CROSS JOIN
, создает декартово произведение целых таблиц, "ключи объединения" не указываются.
JOIN
без указанного типа подразумевает INNER
. Ключевое слово OUTER
можно безопасно опустить. Альтернативный синтаксис для CROSS JOIN
- указание нескольких таблиц в клаузе FROM, разделенных запятыми.
Дополнительные типы объединения, доступные в ClickHouse:
LEFT SEMI JOIN
иRIGHT SEMI JOIN
, белый список по "ключам объединения", без создания декартова произведения.LEFT ANTI JOIN
иRIGHT ANTI 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
поддерживаются только с ALL
строгостью (SEMI
, ANTI
, ANY
и ASOF
не поддерживаются).
Настройки
Тип объединения по умолчанию можно переопределить с помощью настройки join_default_strictness.
Поведение сервера ClickHouse для операций ANY JOIN
зависит от настройки any_join_distinct_right_table_keys.
См. также
- join_algorithm
- join_any_take_last_row
- join_use_nulls
- partial_merge_join_rows_in_right_blocks
- join_on_disk_max_files_to_merge
- any_join_distinct_right_table_keys
Используйте настройку cross_to_inner_join_rewrite
, чтобы определить поведение, когда ClickHouse не может переписать CROSS JOIN
как INNER JOIN
. Значение по умолчанию - 1
, что позволяет продолжить выполнение объединения, но оно будет медленнее. Установите cross_to_inner_join_rewrite
в 0
, если вы хотите, чтобы возникла ошибка, и установите его в 2
, чтобы не выполнять кросс-объединения, а вместо этого принудительно переписать все запятые/кросс объединения. Если переписывание не удастся при значении 2
, вы получите сообщение об ошибке с текстом "Пожалуйста, попробуйте упростить секцию WHERE
".
Условия секции ON
Секция ON
может содержать несколько условий, объединенных с помощью операторов AND
и OR
. Условия, указывающие ключи объединения, должны ссылаться как на левую, так и на правую таблицы и должны использовать оператор равенства. Другие условия могут использовать другие логические операторы, но они должны ссылаться либо на левую, либо на правую таблицу запроса.
Строки объединяются, если выполнено все сложное условие. Если условия не выполнены, строки все еще могут быть включены в результат в зависимости от типа JOIN
. Обратите внимание, что, если те же условия находятся в секции WHERE
и они не выполнены, то строки всегда отфильтровываются из результата.
Оператор OR
внутри клаузулы ON
работает с использованием алгоритма хеш-объединения — для каждого аргумента OR
с ключами объединения для JOIN
создается отдельная хеш-таблица, поэтому использование памяти и время выполнения запроса линейно увеличиваются с увеличением числа выражений OR
клаузулы ON
.
Если условие ссылается на столбцы из разных таблиц, то в текущий момент поддерживается только оператор равенства (=
).
Пример
Рассмотрим table_1
и table_2
:
Запрос с одним условием ключа объединения и дополнительным условием для table_2
:
Обратите внимание, что результат включает строку с именем C
и пустой столбец текста. Она включена в результат, потому что используется тип объединения OUTER
.
Запрос с типом объединения INNER
и несколькими условиями:
Результат:
Запрос с типом объединения INNER
и условием с OR
:
Результат:
Запрос с типом объединения 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
, обратите внимание на раздел ниже для получения дополнительных сведений.
Результат:
Объединение с неравными условиями для столбцов из разных таблиц
На данный момент ClickHouse поддерживает ALL/ANY/SEMI/ANTI INNER/LEFT/RIGHT/FULL 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
полезен, когда вам нужно объединить записи, которые не имеют точного совпадения.
Алгоритм требует специального столбца в таблицах. Этот столбец:
- Должен содержать упорядоченную последовательность.
- Может быть одним из следующих типов: Int, UInt, Float, Date, DateTime, Decimal.
- Для алгоритма хеширования он не может быть единственным столбцом в клаузе
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
для соединения по равенству и asof_column
для соединения по ближайшему совпадению с условием table_1.asof_column >= table_2.asof_column
. Столбец asof_column
всегда находится последним в клаузе USING
.
Например, рассмотрим следующие таблицы:
table_1 table_2 event | ev_time | user_id event | ev_time | user_id ----------|---------|---------- ----------|---------|---------- ... ... event_1_1 | 12:00 | 42 event_2_1 | 11:59 | 42 ... event_2_2 | 12:30 | 42 event_1_2 | 13:00 | 42 event_2_3 | 13:00 | 42 ... ...
ASOF JOIN
может взять метку времени события пользователя из table_1
и найти событие в table_2
, где метка времени находится ближайшей к метке времени события из table_1
, соответствуя условиям ближайшего совпадения. Равные значения меток времени являются ближайшими, если они доступны. Здесь столбец user_id
можно использовать для объединения по равенству, а столбец ev_time
— для объединения по ближайшему совпадению. В нашем примере event_1_1
может быть объединен с event_2_1
, а event_1_2
может быть объединен с event_2_3
, но event_2_2
не может быть объединен.
ASOF JOIN
поддерживается только алгоритмами объединения hash
и full_sorting_merge
.
Он не поддерживается в движке таблиц Join.
Использование PASTE JOIN
Результат PASTE JOIN
— это таблица, которая содержит все столбцы из левого подзапроса, за которыми следуют все столбцы из правого подзапроса.
Строки сопоставляются на основе их позиций в исходных таблицах (порядок строк должен быть определен).
Если подзапросы возвращают различное количество строк, лишние строки будут вырезаны.
Пример:
Примечание: В этом случае результат может быть недетерминированным, если чтение осуществляется параллельно. Пример:
Распределенное JOIN
Существует два способа выполнить объединение с использованием распределенных таблиц:
- Когда используется обычный
JOIN
, запрос отправляется на удаленные серверы. Подзапросы выполняются на каждом из них, чтобы сформировать правую таблицу, и объединение выполняется с этой таблицей. Иными словами, правая таблица формируется на каждом сервере отдельно. - Когда используется
GLOBAL ... JOIN
, сначала сервер-запросчик выполняет подзапрос для вычисления правой таблицы. Эта временная таблица передается на каждый удаленный сервер, и запросы выполняются на них, используя переданные временные данные.
Будьте осторожны при использовании GLOBAL
. Для получения дополнительной информации ознакомьтесь с разделом Распределенные подзапросы.
Неявное приведение типов
Запросы INNER JOIN
, LEFT JOIN
, RIGHT JOIN
и FULL JOIN
поддерживают неявное приведение типов для "ключей объединения". Однако запрос не может быть выполнен, если ключи объединения из левой и правой таблиц не могут быть приведены к одному типу (например, не существует типа данных, который может содержать все значения из обоих UInt64
и Int64
, или String
и Int32
).
Пример
Рассмотрим таблицу t_1
:
и таблицу t_2
:
Запрос
возвращает множество:
Рекомендации по использованию
Обработка пустых или NULL ячеек
Во время объединения таблиц могут появляться пустые ячейки. Настройка join_use_nulls определяет, как ClickHouse заполняет эти ячейки.
Если ключи JOIN
являются Nullable полями, строки, где хотя бы один из ключей имеет значение NULL, не объединяются.
Синтаксис
Столбцы, указанные в USING
, должны иметь одинаковые имена в обеих подзапросах, а другие столбцы должны иметь разные имена. Вы можете использовать псевдонимы, чтобы изменить имена столбцов в подзапросах.
Клаузула USING
указывает один или несколько столбцов для объединения, что устанавливает равенство этих столбцов. Список столбцов задается без скобок. Более сложные условия объединения не поддерживаются.
Ограничения синтаксиса
Для нескольких клауз в JOIN
в одном запросе SELECT
:
- Взять все столбцы с помощью
*
доступно только в случае объединения таблиц, а не подзапросов. - Клаузула
PREWHERE
недоступна. - Клаузула
USING
недоступна.
Для клауз ON
, WHERE
и GROUP BY
:
- Произвольные выражения не могут использоваться в клаузах
ON
,WHERE
иGROUP BY
, но вы можете определить выражение в клаузеSELECT
, а затем использовать его в этих клаузах через псевдоним.
Производительность
Когда выполняется JOIN
, нет оптимизации порядка выполнения относительно других этапов запроса. Объединение (поиск в правой таблице) выполняется до фильтрации в WHERE
и до агрегации.
Каждый раз, когда выполняется запрос с тем же JOIN
, подзапрос выполняется снова, поскольку результат не кешируется. Чтобы избежать этого, используйте специальный движок таблицы Join, который представляет собой подготовленный массив для объединения, который всегда находится в ОЗУ.
В некоторых случаях более эффективно использовать IN, чем JOIN
.
Если вам нужен JOIN
для объединения с измерениями (это относительно небольшие таблицы, которые содержат свойства измерений, такие как названия рекламных кампаний), JOIN
может быть не самым удобным из-за того, что правую таблицу повторно запрашивают для каждого запроса. Для таких случаев есть функция "словари", которую следует использовать вместо JOIN
. Для получения дополнительной информации смотрите раздел Словари.
Ограничения памяти
По умолчанию ClickHouse использует алгоритм хеш-объединения. ClickHouse берет right_table
и создает для нее хеш-таблицу в ОЗУ. Если join_algorithm = 'auto'
включен, то после достижения определенного порога использования памяти ClickHouse переходит на алгоритм merge. Для описания алгоритмов объединения см. настройку join_algorithm.
Если вам необходимо ограничить потребление памяти при операции JOIN
, используйте следующие настройки:
- max_rows_in_join — ограничивает количество строк в хеш-таблице.
- max_bytes_in_join — ограничивает размер хеш-таблицы.
Когда любое из этих ограничений будет достигнуто, ClickHouse будет действовать в соответствии с настройкой join_overflow_mode.
Примеры
Пример: