TL;DR — Resumo Rápido
Guia completo do ClickHouse: armazenamento colunar, motores MergeTree, replicação, views materializadas, ingestão de dados e exemplo de log analytics.
ClickHouse é um DBMS orientado a colunas de código aberto, construído para consultas OLAP em tempo real em escala. Desenvolvido pelo Yandex em 2016, processa bilhões de linhas por segundo em hardware convencional combinando armazenamento colunar, execução vetorizada de consultas e compressão agressiva de dados.
Pré-requisitos
- Host Linux ou Docker com pelo menos 4 GB de RAM (16 GB+ recomendado para produção).
- Conhecimentos básicos de SQL.
- Para replicação: ZooKeeper 3.6+ ou ClickHouse Keeper (incluído desde v22.4).
Arquitetura do ClickHouse
Armazenamento Colunar
Bancos de dados relacionais tradicionais armazenam todas as colunas de uma linha juntas no disco. O ClickHouse armazena cada coluna em um arquivo separado. Quando uma consulta toca apenas 3 de 100 colunas, o ClickHouse lê aproximadamente 3% dos dados. Essa afinidade colunar também permite melhores taxas de compressão porque valores similares repetidos são empacotados de forma eficiente.
Execução Vetorizada de Consultas
O ClickHouse processa dados em lotes de 8.192–65.536 linhas por vez. Instruções SIMD da CPU operam simultaneamente em vetores inteiros de valores. Combinado com a compilação de consultas via LLVM, as agregações que levariam minutos em um banco orientado a linhas são concluídas em segundos.
Família de Motores MergeTree
| Motor | Melhor Para |
|---|---|
| MergeTree | Análise append-only, motor base |
| ReplacingMergeTree | Deduplicação last-write-wins |
| SummingMergeTree | Contadores e somas pré-agregados |
| AggregatingMergeTree | Estados de agregação (com views materializadas) |
| CollapsingMergeTree | Linhas mutáveis via coluna de sinal |
| ReplicatedMergeTree | Replicação HA via Keeper/ZooKeeper |
Compressão de Dados
O ClickHouse usa LZ4 por padrão e suporta ZSTD. Codecs por coluna se empilham: CODEC(Delta, LZ4) reduz colunas de timestamps em mais de 90%. Taxas de compressão típicas são de 5–15× sobre os dados brutos.
Instalação
apt (Ubuntu/Debian)
apt-get install -y apt-transport-https ca-certificates curl gnupg
curl -fsSL 'https://packages.clickhouse.com/rpm/lts/repodata/repomd.xml.key' \
| gpg --dearmor -o /usr/share/keyrings/clickhouse-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/clickhouse-keyring.gpg] \
https://packages.clickhouse.com/deb stable main" \
> /etc/apt/sources.list.d/clickhouse.list
apt-get update && apt-get install -y clickhouse-server clickhouse-client
systemctl enable --now clickhouse-server
Docker
docker run -d \
--name clickhouse \
--ulimit nofile=262144:262144 \
-p 8123:8123 -p 9000:9000 \
-v clickhouse-data:/var/lib/clickhouse \
clickhouse/clickhouse-server:latest
Configuração Inicial
config.xml
<listen_host>0.0.0.0</listen_host>
<path>/var/lib/clickhouse/</path>
users.xml — Perfis e Cotas
<profiles>
<default>
<max_memory_usage>10000000000</max_memory_usage>
<max_threads>8</max_threads>
</default>
</profiles>
Design de Tabelas
CREATE TABLE eventos
(
data_evento Date,
hora_evento DateTime64(3),
user_id UInt64,
acao LowCardinality(String),
receita Decimal(18, 4)
)
ENGINE = MergeTree()
PARTITION BY toYYYYMM(data_evento)
ORDER BY (acao, user_id, hora_evento);
Use LowCardinality(String) para colunas com menos de 10.000 valores distintos. Evite Nullable sempre que possível — use valores sentinela como '' ou 0.
Ingestão de Dados
# Cliente interativo
clickhouse-client --host=localhost --user=default --password=senha
# Inserção em lote a partir de CSV
clickhouse-client --query="INSERT INTO eventos FORMAT CSVWithNames" < eventos.csv
Motor Kafka
CREATE TABLE eventos_kafka ( ... )
ENGINE = Kafka
SETTINGS kafka_broker_list = 'broker:9092',
kafka_topic_list = 'eventos',
kafka_group_name = 'clickhouse-consumer',
kafka_format = 'JSONEachRow';
CREATE MATERIALIZED VIEW eventos_mv TO eventos AS
SELECT * FROM eventos_kafka;
Views Materializadas
CREATE TABLE eventos_por_hora
(
acao LowCardinality(String),
hora DateTime,
cnt AggregateFunction(count),
receita AggregateFunction(sum, Decimal(18,4))
)
ENGINE = AggregatingMergeTree()
ORDER BY (acao, hora);
CREATE MATERIALIZED VIEW eventos_por_hora_mv
TO eventos_por_hora AS
SELECT acao,
toStartOfHour(hora_evento) AS hora,
countState() AS cnt,
sumState(receita) AS receita
FROM eventos
GROUP BY acao, hora;
Replicação e Fragmentação
CREATE TABLE eventos ON CLUSTER meu_cluster
( ... )
ENGINE = ReplicatedMergeTree(
'/clickhouse/tables/{shard}/eventos', '{replica}'
)
PARTITION BY toYYYYMM(data_evento)
ORDER BY (acao, user_id, hora_evento);
CREATE TABLE eventos_dist ON CLUSTER meu_cluster
AS eventos
ENGINE = Distributed(meu_cluster, default, eventos, rand());
ClickHouse vs Alternativas
| ClickHouse | TimescaleDB | Apache Druid | DuckDB | BigQuery | Elasticsearch | |
|---|---|---|---|---|---|---|
| Armazenamento | Colunar | Linha + compressão | Segmentos columnares | Colunar | Colunar | Índice invertido |
| Velocidade | Muito alta | Alta | Alta | Muito alta | Alta | Média |
| Ingestão | Muito alta | Alta | Alta | Baixa | Alta | Alta |
| Streaming | Motor Kafka | Aggs contínuas | Nativo | Não | Pub/Sub | Logstash |
| Auto-hospedado | Sim | Sim | Sim | Sim | Não | Sim |
| Melhor para | OLAP/logs/eventos | Séries temporais | Eventos | Arquivos locais | DW serverless | Busca texto |
Exemplo Prático: Log Analytics
CREATE TABLE nginx_logs
(
data_log Date,
hora_log DateTime64(3),
ip_cliente IPv4,
metodo LowCardinality(String),
uri String,
status UInt16,
bytes UInt64,
tempo_req Float32
)
ENGINE = MergeTree()
PARTITION BY data_log
ORDER BY (status, hora_log)
TTL data_log + INTERVAL 90 DAY DELETE;
Armadilhas e Casos Especiais
- FINAL é custoso — Evite
SELECT ... FINALem tabelas grandes; agendeOPTIMIZE TABLE ... FINALfora do horário de pico. - Inserts pequenos destroem o desempenho — Agrupe sempre pelo menos 10.000 linhas por INSERT ou ative
async_insert = 1. - Ordem do JOIN — O lado direito do JOIN é carregado na memória. Coloque sempre a tabela menor à direita.
- Particionamento excessivo — Particionar por dia em tabelas de alto volume cria muitos fragmentos pequenos. Prefira partições mensais.
Resumo
- Armazenamento colunar + vetorizado oferece agregações 100-1000× mais rápidas para cargas analíticas.
- A família MergeTree cobre deduplicação, pré-agregação e mutabilidade.
- O design do esquema é a alavanca de ajuste mais impactante:
ORDER BYpara padrões de consulta,PARTITION BYpara retenção. - Views materializadas +
AggregatingMergeTreecriam pipelines de agregação com latência zero. - Os motores Kafka e S3 eliminam o ETL externo para ingestão em streaming e em lote.