Pular para o conteúdo principal

Por que usar o ClickHouse Cloud em vez do BigQuery?

TLDR: Porque o ClickHouse é mais rápido, mais barato e mais potente que o BigQuery para análise de dados moderna:

Carregar dados do BigQuery para o ClickHouse Cloud

Conjunto de dados

Como exemplo de conjunto de dados para ilustrar uma migração típica do BigQuery para o ClickHouse Cloud, usamos o conjunto de dados do Stack Overflow documentado aqui. Ele contém todos os post, vote, user, comment e badge registrados no Stack Overflow de 2008 até abril de 2024. O esquema do BigQuery para esses dados é mostrado abaixo: Para os usuários que desejam carregar esse conjunto de dados em uma instância do BigQuery para testar as etapas de migração, fornecemos os dados dessas tabelas em formato Parquet em um GCS bucket, e os comandos DDL para criar e carregar as tabelas no BigQuery estão disponíveis aqui.

Migração de dados

A migração de dados entre o BigQuery e o ClickHouse Cloud se enquadra em dois tipos principais de workload:
  • Carga inicial em massa com atualizações periódicas - Um conjunto de dados inicial precisa ser migrado junto com atualizações periódicas em intervalos definidos, por exemplo, diariamente. Aqui, as atualizações são feitas reenviando as linhas que foram alteradas, identificadas por uma coluna que possa ser usada para comparação (por exemplo, uma data). As exclusões são tratadas com uma recarga periódica completa do conjunto de dados.
  • Replicação em tempo real ou CDC - Um conjunto de dados inicial precisa ser migrado. As alterações nesse conjunto de dados precisam ser refletidas no ClickHouse quase em tempo real, sendo aceitável apenas um atraso de alguns segundos. Na prática, isso é um processo de captura de dados de alteração (CDC), em que as tabelas no BigQuery precisam ser sincronizadas com o ClickHouse, ou seja, inserções, atualizações e exclusões na tabela do BigQuery precisam ser aplicadas a uma tabela equivalente no ClickHouse.

Carregamento em massa via Google Cloud Storage (GCS)

O BigQuery oferece suporte à exportação de dados para o armazenamento de objetos do Google (GCS). Para nosso conjunto de dados de exemplo:
  1. Exporte as 7 tabelas para o GCS. Os comandos para isso estão disponíveis aqui.
  2. Importe os dados para o ClickHouse Cloud. Para isso, podemos usar a função de tabela gcs. O DDL e as consultas de importação estão disponíveis aqui. Observe que, como uma instância do ClickHouse Cloud é composta por vários nós de processamento, em vez da função de tabela gcs, estamos usando a função de tabela s3Cluster. Essa função também funciona com buckets do GCS e utiliza todos os nós de um serviço do ClickHouse Cloud para carregar os dados em paralelo.
Essa abordagem tem várias vantagens: Antes de testar os exemplos a seguir, recomendamos que os usuários consultem as permissões necessárias para exportação e as recomendações sobre localidade dos dados para maximizar o desempenho da exportação e da importação.

Replicação em tempo real ou CDC por meio de consultas agendadas

Captura de dados de alteração (CDC) é o processo pelo qual tabelas são mantidas sincronizadas entre dois bancos de dados. Isso é consideravelmente mais complexo quando atualizações e exclusões precisam ser tratadas quase em tempo real. Uma abordagem é simplesmente agendar uma exportação periódica usando a funcionalidade de consultas agendadas do BigQuery. Desde que você possa aceitar algum atraso na inserção dos dados no ClickHouse, essa abordagem é fácil de implementar e manter. Um exemplo é apresentado neste post do blog.

Projetando esquemas

O conjunto de dados do Stack Overflow contém várias tabelas relacionadas. Recomendamos focar primeiro na migração da tabela principal. Ela não será necessariamente a maior tabela, mas sim aquela sobre a qual você espera fazer o maior número de consultas analíticas. Isso permitirá que você se familiarize com os principais conceitos do ClickHouse. Essa tabela pode exigir remodelagem à medida que tabelas adicionais forem sendo acrescentadas, para explorar plenamente os recursos do ClickHouse e obter o melhor desempenho. Exploramos esse processo de modelagem em nossa documentação de modelagem de dados. Seguindo esse princípio, focamos na tabela principal posts. O esquema do BigQuery correspondente é mostrado abaixo:

Otimizando tipos

Ao aplicar o processo descrito aqui, obtém-se o seguinte esquema:
Podemos popular esta tabela com um INSERT INTO SELECT simples, lendo os dados exportados do gcs com a função de tabela gcs. Observe que, no ClickHouse Cloud, você também pode usar a função de tabela s3Cluster, compatível com gcs, para paralelizar o carregamento em vários nós:
Não mantemos valores NULL no nosso novo esquema. O insert acima os converte implicitamente nos valores padrão dos respectivos tipos - 0 para inteiros e string vazia para strings. O ClickHouse também converte automaticamente qualquer valor numérico para a precisão de destino.

Como as chaves primárias do ClickHouse são diferentes?

Como descrito aqui, assim como no BigQuery, o ClickHouse não impõe unicidade aos valores da coluna de chave primária de uma tabela. Assim como no clustering do BigQuery, os dados de uma tabela do ClickHouse são armazenados em disco em ordem pelas colunas da chave primária. Essa ordenação é usada pelo otimizador de consultas para evitar reordenações, minimizar o uso de memória em junções e permitir interrupção antecipada em cláusulas de limite. Ao contrário do BigQuery, o ClickHouse cria automaticamente um índice primário (esparso) com base nos valores das colunas da chave primária. Esse índice é usado para acelerar todas as consultas que contêm filtros nas colunas da chave primária. Especificamente:
  • Eficiência de memória e de disco é fundamental na escala em que o ClickHouse costuma ser usado. Os dados são gravados nas tabelas do ClickHouse em fragmentos chamados partes, com regras aplicadas para mesclar essas partes em segundo plano. No ClickHouse, cada parte tem seu próprio índice primário. Quando as partes são mescladas, os índices primários da parte resultante também são mesclados. Observe que esses índices não são criados para cada linha. Em vez disso, o índice primário de uma parte tem uma entrada de índice por grupo de linhas — essa técnica é chamada de indexação esparsa.
  • A indexação esparsa é possível porque o ClickHouse armazena em disco as linhas de uma parte ordenadas por uma chave especificada. Em vez de localizar diretamente linhas individuais (como um índice baseado em B-Tree), o índice primário esparso permite identificar rapidamente (por meio de uma busca binária nas entradas do índice) grupos de linhas que podem corresponder à consulta. Os grupos localizados de linhas potencialmente correspondentes são então transmitidos em paralelo para o engine do ClickHouse a fim de encontrar as correspondências. Esse projeto de índice permite que o índice primário seja pequeno (cabendo inteiramente na memória principal) e, ainda assim, acelere significativamente o tempo de execução das consultas, especialmente em consultas de intervalo, típicas de casos de uso de análise de dados. Para mais detalhes, recomendamos este guia detalhado.
A chave primária selecionada no ClickHouse determinará não apenas o índice, mas também a ordem em que os dados são gravados em disco. Por isso, ela pode afetar drasticamente os níveis de compressão, o que, por sua vez, pode impactar o desempenho das consultas. Uma chave de ordenação que faça com que os valores da maioria das colunas sejam gravados de forma contígua permitirá que o algoritmo de compressão selecionado (e os codecs) compacte os dados com mais eficácia.
Todas as colunas de uma tabela serão ordenadas com base no valor da chave de ordenação especificada, independentemente de estarem incluídas na própria chave. Por exemplo, se CreationDate for usada como chave, a ordem dos valores em todas as outras colunas corresponderá à ordem dos valores na coluna CreationDate. É possível especificar várias chaves de ordenação — isso ordenará os dados com a mesma semântica de uma cláusula ORDER BY em uma consulta SELECT.

Escolhendo uma chave de ordenação

Para ver as considerações e as etapas envolvidas na escolha de uma chave de ordenação, usando a tabela Posts como exemplo, consulte aqui.

Técnicas de modelagem de dados

Recomendamos que os usuários que estão migrando do BigQuery leiam o guia de modelagem de dados no ClickHouse. Este guia usa o mesmo conjunto de dados do Stack Overflow e explora várias abordagens com recursos do ClickHouse.

Partições

Se você vem do BigQuery, provavelmente já conhece o conceito de particionamento de tabelas para melhorar o desempenho e facilitar o gerenciamento de grandes bancos de dados, dividindo as tabelas em partes menores e mais fáceis de administrar, chamadas partições. Esse particionamento pode ser feito usando um intervalo em uma coluna específica (por exemplo, datas), listas definidas ou um hash de uma chave. Isso permite que administradores organizem os dados com base em critérios específicos, como intervalos de datas ou localizações geográficas. O particionamento ajuda a melhorar o desempenho das consultas ao permitir acesso mais rápido aos dados por meio de partition pruning e de uma indexação mais eficiente. Também ajuda em tarefas de manutenção, como backups e remoção de dados, ao permitir operações em partições individuais em vez da tabela inteira. Além disso, o particionamento pode melhorar significativamente a escalabilidade de bancos de dados no BigQuery ao distribuir a carga entre várias partições. No ClickHouse, o particionamento é especificado em uma tabela quando ela é definida inicialmente por meio da cláusula PARTITION BY. Essa cláusula pode conter uma expressão SQL sobre qualquer coluna, e o resultado dela definirá para qual partição uma linha será enviada. As partes de dados são associadas logicamente a cada partição no disco e podem ser consultadas de forma isolada. No exemplo abaixo, particionamos a tabela posts por ano usando a expressão toYear(CreationDate). À medida que linhas são inseridas no ClickHouse, essa expressão é avaliada para cada linha — e então as linhas são direcionadas para a partição resultante na forma de novas partes de dados pertencentes a essa partição.

Aplicações

O particionamento no ClickHouse tem aplicações semelhantes às do BigQuery, mas com algumas diferenças sutis. Mais especificamente:
  • Gerenciamento de dados - No ClickHouse, você deve considerar o particionamento principalmente como um recurso de gerenciamento de dados, e não como uma técnica de otimização de consultas. Ao separar os dados logicamente com base em uma chave, cada partição pode ser gerenciada de forma independente, por exemplo, sendo excluída. Isso permite mover partições e, assim, subconjuntos entre camadas de armazenamento de forma eficiente com base no tempo ou expirar dados/excluí-los com eficiência do cluster. No exemplo abaixo, removemos posts de 2008:
  • Otimização de consultas - Embora as partições possam ajudar no desempenho das consultas, isso depende muito dos padrões de acesso. Se as consultas atingirem apenas algumas partições (idealmente uma só), o desempenho pode melhorar. Em geral, isso só é útil se a chave de particionamento não estiver na chave primária e você estiver filtrando por ela. No entanto, consultas que precisam abranger muitas partições podem ter desempenho pior do que sem particionamento (já que o particionamento pode resultar em mais partes). O benefício de atingir uma única partição será ainda menos perceptível — ou até inexistente — se a chave de particionamento já aparecer no início da chave primária. O particionamento também pode ser usado para otimizar consultas GROUP BY se os valores em cada partição forem únicos. No entanto, em geral, você deve garantir que a chave primária esteja otimizada e só considerar o particionamento como técnica de otimização de consultas em casos excepcionais, quando os padrões de acesso se concentram em um subconjunto específico e previsível dos dados, por exemplo, particionamento por dia, com a maioria das consultas voltada para o último dia.

Recomendações

Você deve considerar o particionamento como uma técnica de gerenciamento de dados. Ele é ideal quando é necessário expirar dados do cluster ao trabalhar com séries temporais; por exemplo, a partição mais antiga pode simplesmente ser removida. Importante: certifique-se de que a expressão da sua chave de particionamento não resulte em um conjunto de alta cardinalidade; ou seja, evite criar mais de 100 partições. Por exemplo, não particione seus dados por colunas de alta cardinalidade, como identificadores ou nomes de clientes. Em vez disso, use o identificador ou nome do cliente como a primeira coluna na expressão ORDER BY.
Internamente, o ClickHouse cria partes para os dados inseridos. À medida que mais dados são inseridos, o número de partes aumenta. Para evitar um número excessivamente alto de partes, o que degradará o desempenho da consulta (porque há mais arquivos para ler), as partes são mescladas em um processo assíncrono em segundo plano. Se o número de partes exceder um limite pré-configurado, o ClickHouse lançará uma exceção durante a inserção na forma de um erro de “partes em excesso”. Isso não deve acontecer em condições normais de operação e só ocorre se o ClickHouse estiver mal configurado ou sendo usado incorretamente, por exemplo, com muitas inserções pequenas. Como as partes são criadas isoladamente por partição, aumentar o número de partições faz com que o número de partes também aumente; ou seja, ele é um múltiplo do número de partições. Portanto, chaves de particionamento de alta cardinalidade podem causar esse erro e devem ser evitadas.

Visões materializadas vs projeções

O conceito de projeções no ClickHouse permite especificar várias cláusulas ORDER BY para uma tabela. Em modelagem de dados do ClickHouse, exploramos como visões materializadas podem ser usadas no ClickHouse para pré-calcular agregações, transformar linhas e otimizar consultas para diferentes padrões de acesso. Neste último caso, fornecemos um exemplo em que a visão materializada envia linhas para uma tabela de destino com uma chave de ordenação diferente da tabela original que recebe inserções. Por exemplo, considere a seguinte consulta:
Esta consulta exige que todas as 90 milhões de linhas sejam varridas (embora rapidamente), pois o UserId não é a chave de ordenação. Anteriormente, resolvemos isso usando uma visão materializada que atuava como uma forma de consulta para o PostId. O mesmo problema pode ser resolvido com uma projeção. O comando abaixo adiciona uma projeção com ORDER BY user_id.
Observe que primeiro precisamos criar a projeção e depois materializá-la. Esse segundo comando faz com que os dados sejam armazenados duas vezes em disco, em duas ordens diferentes. A projeção também pode ser definida quando os dados são criados, como mostrado abaixo, e será mantida automaticamente à medida que os dados forem inseridos.
Se a projeção for criada por meio de um comando ALTER, a criação será assíncrona quando o comando MATERIALIZE PROJECTION for executado. Você pode acompanhar o andamento dessa operação com a consulta a seguir, aguardando is_done=1.
Se repetirmos a consulta acima, veremos que o desempenho melhorou significativamente em troca de armazenamento adicional.
Com um comando EXPLAIN, também confirmamos que a projeção foi usada para processar esta consulta:

Quando usar projeções

As projeções são um recurso atraente para novos usuários, pois são mantidas automaticamente à medida que os dados são inseridos. Além disso, as consultas podem ser enviadas para uma única tabela, na qual as projeções são aproveitadas sempre que possível para acelerar o tempo de resposta. Isso contrasta com as visões materializadas, em que o usuário precisa selecionar a tabela de destino otimizada adequada ou reescrever a consulta, dependendo dos filtros. Isso transfere mais responsabilidade para as aplicações do usuário e aumenta a complexidade no lado do cliente. Apesar dessas vantagens, as projeções trazem algumas limitações inerentes das quais você deve estar ciente e, por isso, devem ser usadas com parcimônia. Para mais detalhes, consulte “visões materializadas versus projeções” Recomendamos usar projeções quando:
  • É necessária uma reordenação completa dos dados. Embora a expressão na projeção possa, em teoria, usar um GROUP BY, as visões materializadas são mais eficazes para manter agregações. O otimizador de consultas também tende a aproveitar mais projeções que usam uma reordenação simples, ou seja, SELECT * ORDER BY x. Você pode selecionar um subconjunto de colunas nessa expressão para reduzir o uso de armazenamento.
  • Os usuários estiverem confortáveis com o aumento associado no uso de armazenamento e com a sobrecarga de gravar os dados duas vezes. Teste o impacto na velocidade de inserção e avalie a sobrecarga de armazenamento.

Reescrevendo consultas do BigQuery no ClickHouse

A seguir, são apresentadas consultas de exemplo que comparam o BigQuery ao ClickHouse. Esta lista tem como objetivo demonstrar como aproveitar os recursos do ClickHouse para simplificar significativamente as consultas. Os exemplos aqui usam o conjunto de dados completo do Stack Overflow (até abril de 2024). Users (com mais de 10 perguntas) que recebem mais visualizações: BigQuery ClickHouse
Quais tags recebem mais visualizações: BigQuery
ClickHouse

Funções de agregação

Sempre que possível, aproveite as funções de agregação do ClickHouse. Abaixo, mostramos o uso da função argMax para calcular a pergunta mais visualizada de cada ano. BigQuery ClickHouse

Condicionais e arrays

Funções condicionais e de arrays tornam as consultas significativamente mais simples. A consulta a seguir calcula as tags (com mais de 10000 ocorrências) que tiveram o maior aumento percentual de 2022 para 2023. Observe como a consulta do ClickHouse abaixo é concisa graças às condicionais, às funções de arrays e à possibilidade de reutilizar aliases nas cláusulas HAVING e SELECT. BigQuery ClickHouse
Isso conclui nosso guia básico para quem está migrando do BigQuery para o ClickHouse. Recomendamos a leitura do guia sobre modelagem de dados no ClickHouse para conhecer melhor os recursos avançados do ClickHouse.
Última modificação em 19 de junho de 2026