Pular para o conteúdo principal
Um dicionário no ClickHouse fornece uma representação em memória de chave-valor de dados de várias fontes internas e externas, otimizada para consultas de busca com latência extremamente baixa. Os dicionários são úteis para:
  • Melhorar o desempenho das consultas, especialmente quando usados com JOINs
  • Enriquecer os dados ingeridos em tempo real sem desacelerar o processo de ingestão

Acelerando junções usando um Dicionário

Dicionários podem ser usados para acelerar um tipo específico de JOIN: o tipo LEFT ANY, em que a chave da junção precisa corresponder ao atributo-chave do armazenamento subjacente de chave-valor. Se esse for o caso, o ClickHouse pode aproveitar o dicionário para executar um Direct Join. Esse é o algoritmo de junção mais rápido do ClickHouse e se aplica quando o motor de tabela da tabela do lado direito oferece suporte a solicitações de chave-valor de baixa latência. O ClickHouse tem três motores de tabela que oferecem isso: Join (que é basicamente uma tabela hash pré-calculada), EmbeddedRocksDB e Dicionário. Vamos descrever a abordagem baseada em dicionário, mas o funcionamento é o mesmo para os três motores. O algoritmo de junção direta exige que a tabela da direita seja baseada em um dicionário, de modo que os dados dessa tabela a serem unidos já estejam presentes na memória na forma de uma estrutura de dados de chave-valor de baixa latência.

Exemplo

Usando o conjunto de dados do Stack Overflow, vamos responder à pergunta: Qual é o post sobre SQL mais controverso no Hacker News? Vamos considerar controversos os posts com números semelhantes de votos positivos e negativos. Calculamos essa diferença absoluta, em que um valor mais próximo de 0 indica maior controvérsia. Vamos supor que o post deva ter pelo menos 10 votos positivos e 10 negativos — posts em que ninguém vota não são muito controversos. Com nossos dados normalizados, esta consulta atualmente exige um JOIN entre as tabelas posts e votes:
Use conjuntos de dados menores no lado direito de JOIN: Esta consulta pode parecer mais verbosa do que o necessário, com a filtragem de PostIds ocorrendo tanto na consulta externa quanto nas subconsultas. Esta é uma otimização de desempenho que garante um tempo de resposta rápido para a consulta. Para obter o melhor desempenho, sempre garanta que o lado direito do JOIN seja o menor conjunto possível. Para ver dicas sobre como otimizar o desempenho de JOIN e entender os algoritmos disponíveis, recomendamos esta série de artigos no blog.
Embora esta consulta seja rápida, ela exige que escrevamos o JOIN com cuidado para obter um bom desempenho. O ideal seria simplesmente filtrar os posts para aqueles que contêm “SQL” antes de analisar as contagens de UpVote e DownVote para o subconjunto de blogs e calcular nossa métrica.

Aplicando um dicionário

Para demonstrar esses conceitos, usamos um dicionário para nossos dados de votos. Como os dicionários geralmente ficam na memória (ssd_cache é a exceção), você deve levar em conta o tamanho dos dados. Confirmando o tamanho da nossa tabela votes:
Os dados serão armazenados sem compressão em nosso dicionário, portanto precisaríamos de pelo menos 4 GB de memória se fôssemos armazenar todas as colunas (não vamos) em um dicionário. O dicionário será replicado em todo o nosso cluster, então essa quantidade de memória precisa ser reservada por nó.
No exemplo abaixo, os dados do nosso dicionário vêm de uma tabela do ClickHouse. Embora essa seja a fonte mais comum de dicionários, há várias fontes compatíveis, incluindo arquivos, http e bancos de dados como o Postgres. Como veremos, os dicionários podem ser atualizados automaticamente, o que é ideal para garantir que pequenos conjuntos de dados sujeitos a mudanças frequentes estejam disponíveis para direct joins.
Nosso dicionário exige uma chave primária sobre a qual os lookups serão feitos. Conceitualmente, isso é idêntico à chave primária de um banco de dados transacional e deve ser único. Nossa consulta acima exige um lookup na chave de join — PostId. Por sua vez, o dicionário deve ser preenchido com o total de votos positivos e negativos por PostId da nossa tabela votes. Aqui está a consulta para obter esses dados do dicionário:
Para criar nosso Dicionário, é preciso usar o DDL a seguir — observe o uso da consulta acima:
Na versão OSS autogerenciada, o comando acima precisa ser executado em todos os nós. No ClickHouse Cloud, o dicionário será replicado automaticamente para todos os nós. Isso foi executado em um nó do ClickHouse Cloud com 64GB de RAM, levando 36s para carregar.
Para confirmar a memória consumida pelo nosso dicionário:
Agora, é possível recuperar os votos positivos e negativos de um PostId específico com uma simples função dictGet. Abaixo, recuperamos os valores da postagem 11227902:
Ao aproveitar isso na consulta anterior, podemos remover o JOIN:
Esta consulta não é apenas muito mais simples, mas também mais de duas vezes mais rápida! Isso poderia ser otimizado ainda mais carregando no dicionário apenas posts com mais de 10 votos positivos e negativos e armazenando apenas um valor de controvérsia pré-calculado.

Enriquecimento em tempo de consulta

Dicionários podem ser usados para consultar valores em tempo de consulta. Esses valores podem ser retornados nos resultados ou usados em agregações. Suponha que criemos um dicionário para mapear IDs de usuário para sua localização:
Podemos usar este dicionário para enriquecer os resultados posteriores:
Assim como no exemplo de join acima, podemos usar o mesmo dicionário para determinar com eficiência de onde se origina a maioria dos posts:

Enriquecimento no momento da indexação

No exemplo acima, usamos um dicionário em tempo de consulta para eliminar um join. Os dicionários também podem ser usados para enriquecer linhas no momento da inserção. Isso normalmente é apropriado se o valor do enriquecimento não muda e está em uma fonte externa que pode ser usada para preencher o dicionário. Nesse caso, enriquecer a linha no momento da inserção evita a busca no dicionário em tempo de consulta. Vamos supor que a Location de um usuário no Stack Overflow nunca mude (na prática, muda) — especificamente, a coluna Location da tabela users. Suponha que queremos fazer uma consulta analítica na tabela de posts por localização. Ela contém um UserId. Um dicionário fornece um mapeamento do ID do usuário para a localização, com base na tabela users:
Omitimos usuários com Id < 0, o que nos permite usar o tipo de dicionário Hashed. Usuários com Id < 0 são usuários do sistema.
Para aproveitar esse dicionário no momento da inserção na tabela Posts, precisamos modificar o schema:
No exemplo acima, Location é declarada como uma coluna MATERIALIZED. Isso significa que o valor pode ser fornecido como parte de uma consulta INSERT e será sempre calculado.
O ClickHouse também oferece suporte a colunas DEFAULT` (em que o valor pode ser inserido ou calculado, caso não seja fornecido).
Para preencher a tabela, podemos usar o habitual INSERT INTO SELECT a partir do S3:
Agora podemos obter o nome do local de onde vem a maioria das postagens:

Tópicos avançados sobre dicionários

Para orientações sobre como escolher layouts de dicionários, quando usar dicionários em vez de junções e como monitorar o uso de dicionários, consulte Boas práticas de dicionários.

Atualizando dicionários

Especificamos um LIFETIME para o dicionário de MIN 600 MAX 900. LIFETIME é o intervalo de atualização do dicionário, e esses valores fazem com que ele seja recarregado periodicamente em um intervalo aleatório entre 600 e 900s. Esse intervalo aleatório é necessário para distribuir a carga na origem do dicionário ao atualizar em um grande número de servidores. Durante as atualizações, a versão antiga de um dicionário ainda pode ser consultada; apenas a carga inicial bloqueia consultas. Observe que definir (LIFETIME(0)) impede a atualização dos dicionários. Os dicionários podem ser recarregados à força usando o comando SYSTEM RELOAD DICTIONARY. Para origens de banco de dados, como ClickHouse e Postgres, você pode configurar uma consulta que atualizará os dicionários apenas se eles realmente tiverem mudado (a resposta da consulta determina isso), em vez de em um intervalo periódico. Mais detalhes podem ser encontrados aqui.

Outros tipos de dicionários

O ClickHouse também oferece suporte a dicionários Hierárquicos, Polygon e de Expressão Regular.

Leitura adicional

Última modificação em 29 de junho de 2026