- 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
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
JOIN entre as tabelas posts e votes:
Use conjuntos de dados menores no lado direito deEmbora esta consulta seja rápida, ela exige que escrevamos oJOIN: Esta consulta pode parecer mais verbosa do que o necessário, com a filtragem dePostIds 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 doJOINseja o menor conjunto possível. Para ver dicas sobre como otimizar o desempenho deJOINe entender os algoritmos disponíveis, recomendamos esta série de artigos no blog.
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
votes:
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:
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:
PostId específico com uma simples função dictGet. Abaixo, recuperamos os valores da postagem 11227902:
Enriquecimento em tempo de consulta
Enriquecimento no momento da indexação
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 comPara aproveitar esse dicionário no momento da inserção na tabela Posts, precisamos modificar o schema:Id < 0, o que nos permite usar o tipo de dicionárioHashed. Usuários comId < 0são usuários do sistema.
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:
Tópicos avançados sobre dicionários
Atualizando dicionários
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
Leitura adicional
- Boas práticas de dicionário — seleção de layout, dicionários vs junções, monitoramento
- Usando Dicionários para Acelerar Consultas
- Configuração avançada de Dicionários