JOIN оператор
JOIN
оператор создает новую таблицу, комбинируя колонки из одной или нескольких таблиц, используя значения, общие для каждой из них. Это общая операция в базах данных с поддержкой SQL, которая соответствует реляционной алгебре для объединений. Специальный случай объединения одной таблицы часто называется "самообъединением".
Синтаксис
Выражения из секции ON
и колонки из секции USING
называются "ключами объединения". Если не указано иное, JOIN
создает декартово произведение строк с совпадающими "ключами объединения", что может привести к результату с гораздо большим количеством строк, чем исходные таблицы.
Поддерживаемые типы 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
, смотрите раздел ниже для получения дополнительной информации.
Результат:
JOIN с неравенством для колонок из разных таблиц
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.
- Для алгоритма объединения
hash
она не может быть единственной колонкой в секции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
.
Например, рассмотрим следующие таблицы:
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 использует алгоритм hash join. ClickHouse берет right_table
и создает хеш-таблицу для него в ОП. Если включена настройка join_algorithm = 'auto'
, то после достижения определенного порога потребления памяти ClickHouse переключается на алгоритм merge объединения. Для описания алгоритмов объединения смотрите настройку join_algorithm.
Если вам необходимо ограничить потребление памяти операции JOIN
, используйте следующие настройки:
- max_rows_in_join — Ограничивает количество строк в хеш-таблице.
- max_bytes_in_join — Ограничивает размер хеш-таблицы.
Когда любое из этих ограничений достигается, ClickHouse действует в соответствии с настройкой join_overflow_mode.
Примеры
Пример:
Связанный контент
- Блог: ClickHouse: A Blazingly Fast DBMS with Full SQL Join Support - Part 1
- Блог: ClickHouse: A Blazingly Fast DBMS with Full SQL Join Support - Under the Hood - Part 2
- Блог: ClickHouse: A Blazingly Fast DBMS with Full SQL Join Support - Under the Hood - Part 3
- Блог: ClickHouse: A Blazingly Fast DBMS with Full SQL Join Support - Under the Hood - Part 4