IN, NOT IN, GLOBAL IN e GLOBAL NOT IN são tratados separadamente, pois sua funcionalidade é bastante abrangente.
O lado esquerdo do operador é uma única coluna ou uma tupla.
Exemplos:
SELECT entre parênteses.
Por compatibilidade histórica, quando o lado direito é uma única expressão tuple, ela pode ser interpretada como um conjunto de valores ou como um único valor de tupla, dependendo do lado esquerdo do operador IN. Se o lado esquerdo for um valor escalar, o ClickHouse trata os elementos dessa única expressão tuple no lado direito como valores IN separados:
Query
Response
SELECT 1 IN (1, 2). Se o lado esquerdo também for uma tupla, o lado direito é interpretado como um conjunto de valores de tupla:
Query
Response
tuple. Um lado esquerdo escalar não pode ser comparado a um lado direito que contém múltiplos valores de tuple:
Query
Response
IN.
Nesse caso, ele converte o valor do lado direito para o tipo do lado esquerdo, como
se a função accurateCastOrNull fosse aplicada ao lado direito.
Isso significa que o tipo de dado se torna Nullable e, se a conversão
não puder ser realizada, retorna NULL.
Exemplo
Query
Response
UserID IN users), isso é equivalente à subconsulta UserID IN (SELECT * FROM users). Utilize esse recurso ao trabalhar com dados externos enviados junto com a consulta. Por exemplo, a consulta pode ser enviada junto com um conjunto de IDs de usuário carregados na tabela temporária ‘users’, que deve ser filtrada.
Se o lado direito do operador for um nome de tabela que utiliza o engine Set (um conjunto de dados preparado que fica sempre em RAM), o conjunto de dados não será recriado a cada consulta.
A subconsulta pode especificar mais de uma coluna para filtrar tuplas.
Exemplo:
Query
IN devem ter o mesmo tipo.
O operador IN e a subconsulta podem aparecer em qualquer parte da consulta, inclusive em funções de agregação e funções lambda.
Exemplo:
Query
Response
IN é sempre executada apenas uma vez, em um único servidor. Não há subconsultas dependentes.
Processamento de NULL
IN considera que o resultado de uma operação com NULL é sempre igual a 0, independentemente de NULL estar à direita ou à esquerda do operador. Os valores NULL não são incluídos em nenhum conjunto de dados, não correspondem entre si e não podem ser comparados se transform_null_in = 0.
Aqui está um exemplo com a tabela t_null:
SELECT x FROM t_null WHERE y IN (NULL,3), você obtém o seguinte resultado:
y = NULL é excluída dos resultados da consulta. Isso acontece porque o ClickHouse não consegue determinar se NULL está incluído no conjunto (NULL,3), retorna 0 como resultado da operação, e o SELECT exclui essa linha da saída final.
Subconsultas Distribuídas
IN com subconsultas (semelhante aos operadores JOIN): o IN / JOIN normal e o GLOBAL IN / GLOBAL JOIN. Elas diferem na forma como são executadas no processamento distribuído de consultas.
Lembre-se de que os algoritmos descritos abaixo podem funcionar de forma diferente, dependendo da configuração
distributed_product_mode em configurações.IN regular, a consulta é enviada para servidores remotos, e cada um deles executa as subconsultas na cláusula IN ou JOIN.
Ao usar GLOBAL IN / GLOBAL JOIN, primeiro todas as subconsultas são executadas para GLOBAL IN / GLOBAL JOIN, e os resultados são coletados em tabelas temporárias. Em seguida, as tabelas temporárias são enviadas para cada servidor remoto, onde as consultas são executadas com esses dados temporários.
Para GLOBAL ... JOIN, qual lado da junção é calculado como subconsulta depende do tipo de junção: para junções LEFT e INNER, a tabela da direita é calculada; para junções RIGHT, a tabela da esquerda é calculada, pois a tabela da direita é o lado preservado e deve ser lida a partir dos shards.
Para uma consulta não distribuída, use o IN / JOIN comum.
Tenha cuidado ao usar subconsultas nas cláusulas IN / JOIN para processamento distribuído de consultas.
Vejamos alguns exemplos. Suponha que cada servidor no cluster tenha uma local_table normal. Cada servidor também tem uma tabela distributed_table com o tipo Distributed, que abrange todos os servidores no cluster.
Para uma consulta à distributed_table, a consulta será enviada a todos os servidores remotos e executada neles usando a local_table.
Por exemplo, a consulta
IN:
- Cálculo da interseção entre os públicos de dois sites.
IN será coletado em cada servidor de forma independente, considerando apenas os dados armazenados localmente em cada um dos servidores.
Isso funcionará corretamente e de forma otimizada se você estiver preparado para esse cenário e tiver distribuído os dados entre os servidores do cluster de modo que os dados de um único UserID residam inteiramente em um único servidor. Nesse caso, todos os dados necessários estarão disponíveis localmente em cada servidor. Caso contrário, o resultado será impreciso. Chamamos essa variação da consulta de “local IN”.
Para corrigir o funcionamento da consulta quando os dados estão distribuídos aleatoriamente entre os servidores do cluster, você pode especificar distributed_table dentro de uma subconsulta. A consulta ficaria assim:
GLOBAL IN em vez de IN. Veja como isso funciona para a consulta:
_data1 será enviada para cada servidor remoto junto com a consulta (o nome da tabela temporária é definido pela implementação).
Isso é mais eficiente do que usar o IN normal. No entanto, tenha em mente os seguintes pontos:
- Ao criar uma tabela temporária, os dados não são deduplicados. Para reduzir o volume de dados transmitidos pela rede, especifique DISTINCT na subconsulta. (Você não precisa fazer isso com um
INnormal.) - A tabela temporária será enviada para todos os servidores remotos. A transmissão não leva em conta a topologia da rede. Por exemplo, se 10 servidores remotos estiverem em um datacenter muito distante em relação ao servidor que fez a solicitação, os dados serão enviados 10 vezes pelo canal até o datacenter remoto. Tente evitar grandes conjuntos de dados ao usar
GLOBAL IN. - Ao transmitir dados para servidores remotos, as limitações de largura de banda da rede não são configuráveis. Você pode sobrecarregar a rede.
- Tente distribuir os dados entre os servidores para não precisar usar
GLOBAL INregularmente. - Se você precisar usar
GLOBAL INcom frequência, planeje a localização do cluster ClickHouse para que um único grupo de réplicas não fique distribuído por mais de um data center e haja uma rede rápida entre eles, de modo que uma consulta possa ser processada inteiramente dentro de um único data center.
GLOBAL IN, caso essa tabela local esteja disponível apenas no servidor que fez a solicitação e você queira usar os dados dela em servidores remotos.
Subconsultas distribuídas e max_rows_in_set
max_rows_in_set e max_bytes_in_set para controlar o volume de dados transferidos durante consultas distribuídas.
Isso é especialmente importante se a consulta GLOBAL IN retornar uma grande quantidade de dados. Considere o SQL a seguir:
some_predicate não for seletivo o suficiente, ele retornará uma grande quantidade de dados e causará problemas de desempenho. Nesses casos, é recomendável limitar a transferência de dados pela rede. Observe também que set_overflow_mode está definido como throw (por padrão), o que significa que uma exceção será gerada quando esses limites forem atingidos.
Subconsultas distribuídas e max_parallel_replicas
M está entre 1 e 3, dependendo da réplica em que a consulta local está sendo executada.
Essas configurações afetam todas as tabelas da família MergeTree na consulta e têm o mesmo efeito que aplicar SAMPLE 1/3 OFFSET (M-1)/3 a cada tabela.
Portanto, adicionar a configuração max_parallel_replicas só produzirá resultados corretos se ambas as tabelas tiverem o mesmo esquema de replicação e usarem amostragem por UserID ou por uma subchave dele. Em particular, se local_table_2 não tiver uma chave de amostragem, serão gerados resultados incorretos. A mesma regra se aplica a JOIN.
Uma alternativa, caso local_table_2 não atenda aos requisitos, é usar GLOBAL IN ou GLOBAL JOIN.
Se uma tabela não tiver uma chave de amostragem, podem ser usadas opções mais flexíveis para parallel_replicas_custom_key, que podem resultar em um comportamento diferente e mais otimizado.