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

MotorMelhor Para
MergeTreeAnálise append-only, motor base
ReplacingMergeTreeDeduplicação last-write-wins
SummingMergeTreeContadores e somas pré-agregados
AggregatingMergeTreeEstados de agregação (com views materializadas)
CollapsingMergeTreeLinhas mutáveis via coluna de sinal
ReplicatedMergeTreeReplicaçã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

ClickHouseTimescaleDBApache DruidDuckDBBigQueryElasticsearch
ArmazenamentoColunarLinha + compressãoSegmentos columnaresColunarColunarÍndice invertido
VelocidadeMuito altaAltaAltaMuito altaAltaMédia
IngestãoMuito altaAltaAltaBaixaAltaAlta
StreamingMotor KafkaAggs contínuasNativoNãoPub/SubLogstash
Auto-hospedadoSimSimSimSimNãoSim
Melhor paraOLAP/logs/eventosSéries temporaisEventosArquivos locaisDW serverlessBusca 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 ... FINAL em tabelas grandes; agende OPTIMIZE TABLE ... FINAL fora 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 BY para padrões de consulta, PARTITION BY para retenção.
  • Views materializadas + AggregatingMergeTree criam 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.

Artigos Relacionados