JOIN produz uma nova tabela ao combinar colunas de uma ou mais tabelas com base em valores em comum entre elas. É uma operação comum em bancos de dados com suporte a SQL, correspondente à operação de junção da álgebra relacional. O caso especial de uma junção de uma tabela com ela mesma costuma ser chamado de “self-join”.
Sintaxe
ON e colunas da cláusula USING são chamadas de “chaves de junção”. Salvo indicação em contrário, um JOIN produz um produto cartesiano entre linhas com “chaves de junção” correspondentes, o que pode gerar resultados com muito mais linhas do que as tabelas de origem.
Tipos de JOIN suportados
| Tipo | Descrição |
|---|---|
INNER JOIN | retorna apenas as linhas correspondentes. |
LEFT OUTER JOIN | retorna as linhas não correspondentes da tabela à esquerda, além das linhas correspondentes. |
RIGHT OUTER JOIN | retorna as linhas não correspondentes da tabela à direita, além das linhas correspondentes. |
FULL OUTER JOIN | retorna as linhas não correspondentes de ambas as tabelas, além das linhas correspondentes. |
CROSS JOIN | produz o produto cartesiano das tabelas inteiras; as chaves de junção não são especificadas. |
NATURAL JOIN | faz a junção automaticamente em todas as colunas com o mesmo nome em ambas as tabelas; cada coluna em comum aparece uma única vez no resultado. Suporta as variantes INNER (padrão), LEFT, RIGHT e FULL. Equivale a JOIN ... USING (col1, col2, ...), em que a lista de colunas é derivada automaticamente. |
JOINsem tipo especificado implicaINNER.- A palavra-chave
OUTERpode ser omitida com segurança. - Uma sintaxe alternativa para
CROSS JOINé especificar várias tabelas na cláusulaFROM, separadas por vírgulas. - Se não houver colunas correspondentes para um
NATURAL JOIN, ele funciona como umCROSS JOIN.
| Tipo | Descrição |
|---|---|
LEFT SEMI JOIN, RIGHT SEMI JOIN | Uma lista de permissão nas “chaves de junção”, sem produzir um produto cartesiano. |
LEFT ANTI JOIN, RIGHT ANTI JOIN | Uma lista de bloqueio nas “chaves de junção”, sem produzir um produto cartesiano. |
LEFT ANY JOIN, RIGHT ANY JOIN, INNER ANY JOIN | Desabilita parcialmente (para o lado oposto de LEFT e RIGHT) ou completamente (para INNER e FULL) o produto cartesiano dos tipos padrão de JOIN. |
ASOF JOIN, LEFT ASOF JOIN | Junção de sequências com correspondência não exata. O uso de ASOF JOIN é descrito abaixo. |
PASTE JOIN | Executa uma concatenação horizontal de duas tabelas. |
Quando join_algorithm está definido como
partial_merge, RIGHT JOIN e FULL JOIN são suportados apenas com a strictness ALL (SEMI, ANTI, ANY e ASOF não são suportados).Configurações
join_default_strictness.
O comportamento do servidor do ClickHouse para operações ANY JOIN depende da configuração any_join_distinct_right_table_keys.
Veja também
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 para definir o comportamento quando o ClickHouse não consegue reescrever um CROSS JOIN como um INNER JOIN. O valor padrão é 1, o que permite que a junção continue, mas ela será mais lenta. Defina cross_to_inner_join_rewrite como 0 se quiser que um erro seja gerado e como 2 para não executar os CROSS JOIN, mas sim forçar a reescrita de todas as junções com vírgula ou CROSS JOIN. Se a reescrita falhar quando o valor for 2, você receberá uma mensagem de erro informando “Please, try to simplify WHERE section”.
Condições da seção ON
ON pode conter várias condições combinadas com os operadores AND e OR. As condições que especificam chaves de junção devem:
- referenciar as tabelas da esquerda e da direita
- usar o operador de igualdade
JOIN. Observe que, se as mesmas condições forem colocadas em uma seção WHERE e não forem atendidas, as linhas sempre serão filtradas do resultado.
O operador OR dentro da cláusula ON funciona com o algoritmo de hash junção — para cada argumento OR com chaves de junção para JOIN, é criada uma tabela hash separada; assim, o consumo de memória e o tempo de execução da consulta aumentam linearmente à medida que cresce o número de expressões OR na cláusula ON.
Se uma condição referencia colunas de tabelas diferentes, por enquanto só há suporte ao operador de igualdade (
=).table_1 e table_2:
table_2:
Query
C e a coluna de texto vazia. Ela foi incluída no resultado porque foi usada uma junção do tipo OUTER.
Response
INNER e múltiplas condições:
Query
Response
INNER e condição com OR:
Query
Response
INNER como tipo de junção e condições com OR e AND:
Por padrão, condições de desigualdade são aceitas, desde que usem colunas da mesma tabela.
Por exemplo,
t1.a = t2.key AND t1.b > 0 AND t2.b > t2.c, porque t1.b > 0 usa apenas colunas de t1 e t2.b > t2.c usa apenas colunas de t2.
No entanto, você pode testar o suporte experimental para condições como t1.a = t2.key AND t1.b > t2.key; consulte a seção abaixo para mais detalhes.Query
Response
Junção com condições de desigualdade para colunas de tabelas diferentes
ALL/ANY/SEMI/ANTI INNER/LEFT/RIGHT/FULL JOIN com condições de desigualdade, além das condições de igualdade. As condições de desigualdade são compatíveis apenas com os algoritmos de junção hash e grace_hash. As condições de desigualdade não são compatíveis com join_use_nulls.
Exemplo
Tabela t1:
t2
Valores NULL nas chaves de JOIN
NULL não é igual a nenhum valor, nem a si mesmo. Isso significa que, se uma chave de JOIN tiver um valor NULL em uma tabela, ela não corresponderá a um valor NULL na outra tabela.
Exemplo
Tabela A:
B:
Charlie da tabela A e a linha com pontuação 88 da tabela B não aparecem no resultado por causa do valor NULL na chave de JOIN.
Caso você queira fazer a correspondência de valores NULL, use a função isNotDistinctFrom para comparar as chaves de JOIN.
Uso do ASOF JOIN
ASOF JOIN é útil quando você precisa combinar registros que não têm correspondência exata.
Este algoritmo de junção exige uma coluna especial nas tabelas. Essa coluna:
- Deve conter uma sequência ordenada.
- Pode ser de um dos seguintes tipos: Int, UInt, Float, Date, DateTime, Decimal.
- No algoritmo de junção
hash, ela não pode ser a única coluna na cláusulaJOIN.
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.
Condições aceitas para a correspondência mais próxima: >, >=, <, <=.
Sintaxe de ASOF JOIN ... USING:
ASOF JOIN usa equi_columnX para fazer a junção por igualdade e asof_column para fazer a junção pela correspondência mais próxima com a condição table_1.asof_column >= table_2.asof_column. A coluna asof_column é sempre a última na cláusula USING.
Por exemplo, considere as tabelas a seguir:
ASOF JOIN pode usar o timestamp de um evento de usuário de table_1 e encontrar um evento em table_2 cujo timestamp seja o mais próximo do timestamp do evento de table_1, de acordo com a condição de correspondência mais próxima. Valores de timestamp iguais são considerados os mais próximos, quando disponíveis. Aqui, a coluna user_id pode ser usada na junção por igualdade, e a coluna ev_time pode ser usada na junção pela correspondência mais próxima. No nosso exemplo, event_1_1 pode ser unido a event_2_1 e event_1_2 pode ser unido a event_2_3, mas event_2_2 não pode ser unido.
ASOF JOIN é compatível apenas com os algoritmos de junção hash e full_sorting_merge.
Não é compatível com o mecanismo de tabela Join.Uso do PASTE JOIN
PASTE JOIN é uma tabela que contém todas as colunas da subconsulta à esquerda, seguidas de todas as colunas da subconsulta à direita.
As linhas são associadas com base em suas posições nas tabelas originais (a ordem das linhas deve estar definida).
Se as subconsultas retornarem números diferentes de linhas, as linhas excedentes serão descartadas.
Exemplo:
JOIN distribuído
- Ao usar um
JOINnormal, a consulta é enviada aos servidores remotos. As subconsultas são executadas em cada um deles para montar a tabela da direita, e a junção é realizada com essa tabela. Em outras palavras, a tabela da direita é formada separadamente em cada servidor. - Ao usar
GLOBAL ... JOIN, primeiro o servidor solicitante executa uma subconsulta para calcular um dos lados da junção e armazena o resultado em uma tabela temporária. Essa tabela temporária é então enviada a cada servidor remoto, e as consultas são executadas neles usando os dados temporários transmitidos. Para junçõesLEFTeINNER, a tabela da direita é calculada pela subconsulta. Para junçõesRIGHT, a tabela da esquerda é calculada, já que a tabela da direita é a preservada e deve ser lida dos shards.
GLOBAL. Para mais informações, consulte a seção Subconsultas distribuídas.
Conversão implícita de tipos
INNER JOIN, LEFT JOIN, RIGHT JOIN e FULL JOIN oferecem suporte à conversão implícita de tipos para as “chaves de junção”. No entanto, a consulta não pode ser executada se as chaves de junção das tabelas à esquerda e à direita não puderem ser convertidas para um único tipo (por exemplo, não há nenhum tipo de dado que possa comportar todos os valores de UInt64 e Int64, ou de String e Int32).
Exemplo
Considere a tabela t_1:
t_2:
Recomendações de uso
Processamento de células vazias ou NULL
JOIN entre tabelas, podem surgir células vazias. A configuração join_use_nulls define como o ClickHouse preenche essas células.
Se as chaves de JOIN forem campos Nullable, as linhas em que pelo menos uma das chaves tem o valor NULL não são unidas.
Sintaxe
USING devem ter os mesmos nomes em ambas as subconsultas, e as demais colunas devem ter nomes diferentes. Você pode usar aliases para alterar os nomes das colunas nas subconsultas.
A cláusula USING especifica uma ou mais colunas para unir, estabelecendo a igualdade entre essas colunas. A lista de colunas é definida sem parênteses. Condições de junção mais complexas não são suportadas.
Limitações de sintaxe
JOIN em uma única consulta SELECT:
- Selecionar todas as colunas com
*só é possível quando há junção entre tabelas, e não subconsultas. - A cláusula
PREWHEREnão está disponível. - A cláusula
USINGnão está disponível.
ON, WHERE e GROUP BY:
- Não é possível usar expressões arbitrárias nas cláusulas
ON,WHEREeGROUP BY, mas você pode definir uma expressão em uma cláusulaSELECTe depois usá-la nessas cláusulas por meio de um alias.
Desempenho
JOIN, não há otimização da ordem de execução em relação às outras etapas da consulta. A junção (uma busca na tabela da direita) é executada antes da filtragem em WHERE e antes da agregação.
Sempre que uma consulta é executada com o mesmo JOIN, a subconsulta é executada novamente, porque o resultado não fica em cache. Para evitar isso, use o mecanismo de tabela especial Join, que é um array pré-preparado para junções e permanece sempre na RAM.
Em alguns casos, é mais eficiente usar IN em vez de JOIN.
Se você precisar de um JOIN para fazer junção com tabelas de dimensão (tabelas relativamente pequenas que contêm propriedades de dimensão, como nomes de campanhas publicitárias), um JOIN pode não ser muito prático, já que a tabela da direita é acessada novamente a cada consulta. Nesses casos, existe o recurso “dicionários”, que você deve usar em vez de JOIN. Para mais informações, consulte a seção Dicionários.
Limitações de memória
right_table e cria uma tabela hash para ela na RAM. Se join_algorithm = 'auto' estiver habilitado, após determinado limite de consumo de memória, o ClickHouse passa a usar o algoritmo merge de junção. Para obter uma descrição dos algoritmos de junção, consulte a configuração join_algorithm.
Se você precisar restringir o consumo de memória da operação de junção JOIN, use as seguintes configurações:
- max_rows_in_join — Limita o número de linhas na tabela hash.
- max_bytes_in_join — Limita o tamanho da tabela hash.
Exemplos
- Blog: ClickHouse: um SGBD extremamente rápido com suporte completo a junções SQL - Parte 1
- Blog: ClickHouse: um SGBD extremamente rápido com suporte completo a junções SQL - Nos bastidores - Parte 2
- Blog: ClickHouse: um SGBD extremamente rápido com suporte completo a junções SQL - Nos bastidores - Parte 3
- Blog: ClickHouse: um SGBD extremamente rápido com suporte completo a junções SQL - Nos bastidores - Parte 4