🏗️ Arquitetura de Dados Moderna
Este documento é um manual técnico de referência para engenheiros de software, arquitetos e cientistas de dados — mas com uma escada didática para que um trainee consiga acompanhar. Cada família é analisada sob a ótica da engenharia real: arquitetura interna, trade-offs, anti-padrões documentados e integração com IA moderna. A versão 2.3 incorpora explicações conceituais com analogias simples, um glossário para iniciantes e contextualização de custo e carga operacional (FinOps).
Navegue pela sidebar. As seções seguem o fluxo: tabular (Relacional → Colunar) → agregados (Documento, KV) → distribuídos (Wide-Column) → relacionamentos (Grafo) → especializados (TS, Search, Vetorial). Use Ctrl+K para busca. Termos densos como LSM Tree, MVCC, WAL, Sharding e Cardinalidade estão definidos no Glossário para Trainee.
Se você está começando, leia primeiro o glossário e depois volte. Cada seção tem um bloco "Por baixo dos panos" com analogias do mundo real para os conceitos mais densos.
9 Famílias
Relacional, Colunar, Documento, Key-Value, Wide-Column, Grafo, Time-Series, Search e Vetorial.
Profundidade Técnica
Storage engines, WAL, LSM Trees, MVCC, index-free adjacency, supernodes.
IA Moderna
RAG, embeddings, hybrid search (BM25 + vetor), memória de agentes.
Anti-Padrões
Shard keys monotônicas, ES como fonte de verdade, modelagem relacional no Cassandra.
Como Escolher o Banco de Dados Correto
A escolha não deve ser guiada por hype. É uma decisão arquitetural que impacta latência, throughput, custo operacional, complexidade de código e resiliência a falhas.
Perguntas Fundamentais
- Qual o formato dos dados? Estruturado (tabelas), semiestruturado (JSON), grafos, séries temporais, vetores densos?
- Qual o padrão de acesso? Leitura pesada, escrita pesada, balanceado? Consultas pontuais ou analíticas?
- Qual a latência aceitável? Sub-ms (Redis), ms (PostgreSQL), segundos (BigQuery)?
- Qual o volume de dados? GB, TB, PB?
- Qual o modelo de consistência necessário? ACID estrito ou eventual aceitável?
- Qual a tolerância a falhas? Zero downtime? Recuperação em minutos?
- Qual o orçamento operacional? Self-hosted, managed cloud, serverless?
Matriz de Decisão
| Cenário | Banco Recomendado | Alternativa | Notas |
|---|---|---|---|
| CRUD transacional + integridade | PostgreSQL | MySQL, CockroachDB | ACID mandatório |
| Catálogo / CMS | MongoDB | Couchbase, Firestore | Schema flexível |
| Cache de baixa latência | Redis | Memcached | Sub-ms |
| Event sourcing / IoT | Cassandra | ScyllaDB | Write-heavy |
| Grafos sociais / Recomendação | Neo4j | ArangoDB | Travessia profunda |
| Métricas / monitoring | Prometheus + InfluxDB | TimescaleDB | Time-series nativo |
| Full-text search | Elasticsearch | OpenSearch, Meilisearch | Índice invertido |
| RAG / busca semântica | Pinecone ou Weaviate | PostgreSQL (pgvector) | pgvector se já usa Postgres |
| Analytics / data warehouse | ClickHouse | BigQuery, Snowflake | Colunar, OLAP |
Poliglot Persistence
Prática de usar diferentes tecnologias de armazenamento para diferentes necessidades dentro da mesma aplicação. Um e-commerce moderno pode usar:
- PostgreSQL — pedidos, transações financeiras (ACID)
- Redis — carrinho, sessões, rate limiting
- Elasticsearch — busca de produtos (stemming, relevância)
- Cassandra — eventos de navegação (write-heavy)
- Pinecone — recomendações por similaridade semântica
graph LR
A[API Gateway] --> B[Pedidos]
A --> C[Busca]
A --> D[Recomendação]
B --> E[(PostgreSQL)]
B --> F[(Redis)]
C --> G[(Elasticsearch)]
D --> H[(Pinecone)]
B --> I[(Cassandra)]
1. Bancos Relacionais — Conceito & Modelo
Organizam dados em tabelas com schema rígido. Baseado na álgebra relacional de Codd (1970). Relações por chaves primárias e estrangeiras, garantindo integridade referencial.
Modelo Mental
Pense em um banco relacional como um conjunto matemático de fatos. Cada linha é uma proposição verdadeira. O SQL é declarativo: você descreve o que quer, o query planner decide como obter.
-- DDL + INSERT: como o dado é armazenado
CREATE TABLE pedidos (
id SERIAL PRIMARY KEY,
cliente_id INTEGER NOT NULL REFERENCES clientes(id),
valor_total NUMERIC(12,2) NOT NULL,
status VARCHAR(20) DEFAULT 'pendente',
criado_em TIMESTAMPTZ DEFAULT now()
);
INSERT INTO pedidos (cliente_id, valor_total, status)
VALUES (42, 299.90, 'confirmado');
Características — ACID, CAP & Escalabilidade
ACID
- Atomicidade: WAL garante tudo ou nada.
- Consistência: Constraints e integridade referencial.
- Isolamento: MVCC (PostgreSQL) ou locks (MySQL).
- Durabilidade: WAL + fsync.
CAP Theorem — Contexto Correto
O teorema CAP aplica-se a sistemas distribuídos com replicação. Um PostgreSQL standalone não está sujeito a partições de rede — não há "P" para tolerar. Já bancos NewSQL como CockroachDB são nativamente CP (consistência + tolerância a partições).
Arquitetura Interna — B-Tree, MVCC & VACUUM
A maioria usa B-Trees como estrutura primária de índice. Cada nó ocupa uma página de disco (8KB no PostgreSQL). MVCC permite leituras não bloqueantes via snapshots. O VACUUM limpa versões obsoletas — falha em executá-lo causa bloat e degradação de performance.
B-Tree é como o índice remissivo de uma enciclopédia: as páginas
ficam ordenadas e o índice te leva rapidamente até a entrada certa em poucos saltos
(O log N). Excelente para leitura por chave e busca por intervalo.
WAL (Write-Ahead Log) é como um caderno de rascunho de garçom:
antes de mexer no caixa (disco principal), ele anota tudo na comanda. Se cair a luz,
ao reabrir basta reler a comanda para reconstruir o estado. Garante durabilidade
(D do ACID) sem precisar escrever no disco principal a cada operação.
MVCC (Multi-Version Concurrency Control) é como o Google Docs com
histórico de versões: cada transação enxerga um snapshot consistente do banco e
leituras nunca bloqueiam escritas. O preço é o "lixo" deixado por versões antigas, que
o VACUUM precisa coletar periodicamente.
graph TD
A[Cliente SQL] --> B[Parser]
B --> C[Query Planner]
C --> D[Executor]
D --> E[Storage Engine]
E --> F[B-Tree Index]
E --> G[Heap / Table]
E --> H[WAL Writer]
H --> I[(Write-Ahead Log)]
SQL & Interfaces
-- Window function com cast explícito (evita divisão inteira)
SELECT categoria, produto, receita,
RANK() OVER (PARTITION BY categoria ORDER BY receita DESC) AS rank_cat,
ROUND(receita::numeric / SUM(receita::numeric) OVER (PARTITION BY categoria) * 100, 2) AS pct
FROM vendas_mensais WHERE data >= '2026-01-01'
ORDER BY categoria, rank_cat;
Casos de Uso Reais (Validados)
- Stripe: PostgreSQL para transações financeiras. ACID inegociável. Sharding com Citus.
- Instagram: PostgreSQL com sharding lógico customizado (geração de IDs via PL/pgSQL, roteamento na aplicação). Não usam Vitess — Vitess é uma solução para MySQL criada pelo YouTube.
- Uber: MySQL com Schemaless (camada interna de flexibilidade).
Versões anteriores atribuíam Vitess ao Instagram/PostgreSQL. Isso estava incorreto. O Vitess foi criado pelo YouTube para escalar MySQL. O Instagram desenvolveu seu próprio sistema de sharding para PostgreSQL.
Quando NÃO Usar SQL
- Full-text search: Elasticsearch oferece stemming e BM25 nativos.
- Análise de petabytes: ClickHouse/BigQuery superam row-store.
- Schema altamente variável: MongoDB ou Couchbase mais naturais.
Produtos Relevantes
| Banco | Licença | Destaque | Limitação | Empresas |
|---|---|---|---|---|
| PostgreSQL | MIT-like | Extensível, MVCC, JSONB, pgvector | Replicação multi-master complexa | Stripe, Instagram, Reddit |
| MySQL | GPL/Oracle | Alta adoção, InnoDB robusto | Menos extensível que PG | Uber, GitHub, YouTube |
| SQLite | Public Domain | Embedded, zero-config, single-writer (modo WAL permite leitores concorrentes ao escritor) | Apenas um escritor por vez — contenção em apps com alta concorrência de escrita | iOS, Android, Chrome |
| CockroachDB | BSL | NewSQL, CP nativo, PG wire-compatible | Latência > PG standalone | Bose, Comcast |
Por padrão, o SQLite usa o modo rollback journal, onde leitores
bloqueiam escritores e vice-versa. Ativando o modo WAL (Write-Ahead
Logging) com PRAGMA journal_mode=WAL, leituras passam a
ocorrer em paralelo à escrita em andamento — só não pode haver
dois escritores simultâneos. Essa nuance é vital para performance em apps móveis
e desktop modernos, onde leitura concorrente é a regra.
IA & SQL
PostgreSQL + pgvector permite busca por similaridade de cosseno no SQL, mantendo metadados na mesma base — ideal para RAG sem dupla sincronização.
-- Busca semântica com pgvector
SELECT documento_id, conteudo,
1 - (embedding <=> query_embedding) AS similaridade
FROM documentos ORDER BY embedding <=> query_embedding LIMIT 10;
2. Bancos Colunares / OLAP — Conceito & Row vs Column
Armazenam dados por coluna. Em um row-store (OLTP), todos os campos de uma linha ficam juntos na mesma página. Em um column-store (OLAP), cada coluna é armazenada separadamente, permitindo compressão extrema (10-20x) e scans eficientes para agregações.
Visualização: Como o disco enxerga seus dados
Considere uma tabela de vendas com 4 colunas (id, data,
categoria, valor) e 3 linhas. Veja como cada arquitetura
agrupa os bytes no disco:
graph TB
subgraph ROW["🗄️ Row-Store (PostgreSQL, MySQL) — agrupado por LINHA"]
R1["Bloco 1: [1 | 2026-05-12 | audio | 299.90]"]
R2["Bloco 2: [2 | 2026-05-12 | video | 1499.00]"]
R3["Bloco 3: [3 | 2026-05-13 | audio | 89.50]"]
R1 --> R2 --> R3
end
subgraph COL["📊 Column-Store (ClickHouse, BigQuery) — agrupado por COLUNA"]
C1["Bloco id: [1, 2, 3]"]
C2["Bloco data: [2026-05-12, 2026-05-12, 2026-05-13]"]
C3["Bloco categoria: [audio, video, audio]"]
C4["Bloco valor: [299.90, 1499.00, 89.50]"]
C1 --> C2 --> C3 --> C4
end
Para SELECT SUM(valor) FROM vendas:
• Row-Store: precisa ler TODOS os blocos (id, data, categoria, valor)
para extrair apenas a coluna valor. Desperdício de I/O.
• Column-Store: lê apenas o bloco valor. Bônus: como
valores semelhantes ficam juntos, a compressão chega a 10–20×.
Por isso row-stores ganham em OLTP (ler/atualizar uma linha inteira) e column-stores
ganham em OLAP (agregar uma coluna sobre bilhões de linhas).
-- Query analítica no ClickHouse
SELECT toStartOfDay(data) AS dia, categoria,
SUM(receita) AS total, COUNT(DISTINCT usuario_id) AS usuarios
FROM vendas WHERE data >= today() - 30
GROUP BY dia, categoria ORDER BY dia DESC, total DESC LIMIT 100;
-- Column-store lê apenas 4 colunas; row-store leria TODAS as colunas de cada linha.
⚠️ Colunar (OLAP) ≠ Wide-Column (NoSQL)
Colunar (ClickHouse, BigQuery): foco em compressão e agregações
analíticas. Os dados são organizados por coluna para acelerar scans sequenciais
e funções agregadas (SUM, AVG). Não foi feito para buscas pontuais por chave.
Wide-Column (Cassandra, ScyllaDB): foco em particionamento e
escrita em massa. Os dados são organizados por row key + column families
esparsas. Otimizado para gravações rápidas e disponibilidade, não para agregações
analíticas.
Casos de Uso
- Cloudflare: ClickHouse para análise de trilhões de eventos/dia.
- Spotify: BigQuery para análise de streaming.
- Capital One: Snowflake como data warehouse corporativo.
Produtos
| Banco | Licença | Destaque | Limitação |
|---|---|---|---|
| ClickHouse | Apache 2.0 | Rápido, compressão agressiva | Updates/Deletes custosos |
| BigQuery | GCP Proprietário | Serverless, escala a PB | Custo por query, lock-in |
| Snowflake | Proprietário | Separação storage/compute | Custo elevado |
| DuckDB | MIT | "SQLite para analytics" | Não multi-user |
3. Bancos de Documento — Conceito & Modelo
Armazenam documentos (JSON, BSON). Design orientado a agregados: dados relacionados são embedados, evitando JOINs. Schema flexível por documento.
// Documento MongoDB: dados relacionados embutidos
db.produtos.insertOne({
_id: ObjectId("684f1a2b3c4d5e6f7a8b9c0d"),
nome: "Fone Bluetooth Pro",
categoria: "áudio",
preco: NumberDecimal("299.90"),
variantes: [{ cor: "preto", estoque: 150 }, { cor: "branco", estoque: 80 }],
avaliacoes: [{ usuario: "ana", nota: 4.5, comentario: "Ótimo som" }]
});
Características — Tunable Consistency & Sharding
MongoDB moderno (4.0+) não é puramente BASE. Ele oferece consistência configurável
(tunable consistency): transações ACID multi-documento, leituras com
readConcern: "majority" e escritas com writeConcern: "majority".
O modelo permite escolher entre performance e consistência por operação.
O custo real de subir a consistência
"Tunable" não é mágica: cada degrau acima na consistência custa latência. Veja a ordem de grandeza típica em um replica set de 3 nós:
| Nível | Latência típica | Garantia | Quando usar |
|---|---|---|---|
w:1 (default antigo) | ~1ms | Confirmação só do primário. Perda de dados se ele cair antes de replicar. | Logs, telemetria descartável |
w:majority (default novo) | ~5–15ms | Espera maioria dos nós confirmarem. Sobrevive a falha de 1 nó. | Dados de negócio padrão |
w:majority + j:true | ~10–30ms | Espera fsync no journal de cada nó. Sobrevive a quedas de energia. | Pagamentos, financeiro |
readConcern: "linearizable" | ~20–100ms | Leitura mais recente garantida globalmente. Requer round-trip extra. | Auditoria, regulado |
Subir de eventual para majority custa de 3× a 10× mais
latência. Vale para escritas críticas, é desperdício para logs e métricas.
Configure por operação, não globalmente.
Sharding — Anti-Padrão Documentado
Chaves de alta cardinalidade que crescem monotonamente (ObjectId, timestamp) direcionam todas as novas escritas para o mesmo shard. Use hashed sharding para distribuir escritas uniformemente quando a chave natural for monotônica. Range sharding é útil para queries por intervalo, mas perigoso com chaves sequenciais.
Arquitetura Interna
Storage engine WiredTiger: B-Trees + MVCC + compressão snappy. O oplog registra operações para replicação.
graph TD
A[Driver] --> B[Mongos Router]
B --> C[Config Servers]
B --> D[Shard 1]
B --> E[Shard 2]
D --> F[(WiredTiger)]
E --> G[(WiredTiger)]
Queries & APIs
// Aggregation pipeline
db.vendas.aggregate([
{ $match: { data: { $gte: new Date('2026-04-01') } } },
{ $unwind: '$itens' },
{ $group: { _id: '$itens.categoria', total: { $sum: '$itens.preco' } } },
{ $sort: { total: -1 } }, { $limit: 10 }
]);
Casos de Uso Reais
- Adobe: Creative Cloud — metadados de ativos com schema flexível.
- eBay: Catálogo de produtos com milhões de SKUs.
- Coinbase: Dados de exchange com histórico embutido.
Quando NÃO Usar
- Relacionamentos N:N complexos: Use grafo ou relacional.
- Relatórios analíticos pesados: Aggregation pipeline lento vs SQL colunar.
Produtos
| Banco | Licença | Destaque | Limitação |
|---|---|---|---|
| MongoDB | SSPL/Cloud | Atlas, tunable consistency | RAM alto, licença controversa |
| Couchbase | Apache 2.0 | SQL++ (N1QL), cache integrado | Comunidade menor |
| Firestore | GCP Proprietário | Serverless, real-time | Vendor lock-in |
4. Bancos Key-Value — Conceito & Modelo
Modelo mais simples: chave → valor. Redis estende com listas, sets, sorted sets, hashes, streams. Latências em microssegundos.
// Redis: estruturas de dados
SET usuario:42:session "abc123" EX 3600
LPUSH fila:emails "bem-vindo:joao@exemplo.com"
ZADD ranking:jogadores 1500 "alice" 1420 "bob"
HSET produto:789 nome "Teclado" preco 199.90 estoque 45
Características
O event loop principal do Redis é single-threaded — a execução dos comandos
acontece em uma única thread, o que garante atomicidade sem precisar de locks e dá previsibilidade
de latência. Mas atenção: a partir do Redis 6.0, o
I/O de rede (leitura/parsing de bytes do socket e escrita das respostas) pode
ser delegado a múltiplas threads via io-threads. Em workloads
com muitos clientes concorrentes, isso aumenta o throughput sem quebrar a atomicidade.
Dizer apenas que "Redis é single-threaded" é uma simplificação que pode levar a decisões
ruins (ex: subdimensionar CPU em servidores com muitos clientes). O processamento
de comandos é single-threaded; o I/O de rede não é mais.
Tarefas de background como BGSAVE (RDB), BGREWRITEAOF e expiração
lazy também rodam fora da thread principal.
Persistência: RDB (snapshots) + AOF (append-only file). Cluster com 16384 hash slots para sharding horizontal.
Arquitetura Interna
Estruturas otimizadas: SDS (strings O(1)), Skip Lists (sorted sets O(log N)), Quicklists, Rax (Radix Tree para streams).
graph LR
A[Cliente] --> B[Event Loop]
B --> C{Comando}
C -->|SET| D[Hash Table]
C -->|ZADD| E[Skip List]
D --> F[(RAM)]
Casos de Uso
- Twitter: Timeline cache.
- GitHub: Job queues (Sidekiq), rate limiting.
- OpenAI: Rate limiting e cache de API.
Produtos
| Banco | Licença | Destaque | Limitação |
|---|---|---|---|
| Redis | RSALv2/SSPL | Estruturas ricas, pub/sub, I/O multi-threaded (6.0+) | RAM cara; execução de comandos ainda single-thread |
| DynamoDB | AWS Proprietário | Serverless, auto-scaling | Lock-in |
| Memcached | BSD | Multi-threaded, simples | Sem persistência |
5. Bancos Wide-Column — Conceito & Modelo
Organizam dados em linhas com row key, mas cada linha pode ter colunas diferentes (modelo esparso). Colunas agrupadas em column families. Otimizado para escritas rápidas e escalabilidade horizontal. Não confundir com bancos colunares (OLAP) — veja a distinção na seção 2.
-- CQL (Cassandra): schema
CREATE TABLE eventos_usuario (
usuario_id UUID,
timestamp TIMESTAMP,
tipo TEXT,
payload TEXT,
PRIMARY KEY (usuario_id, timestamp)
) WITH CLUSTERING ORDER BY (timestamp DESC);
Modelagem Query-First — O Paradigma do Wide-Column
Diferentemente do modelo relacional (onde você modela entidades e normaliza), no Cassandra você modela para as queries que vai executar. Isso significa que você pode duplicar dados em múltiplas tabelas para atender a diferentes padrões de acesso. Não há JOINs — cada query deve bater em uma única tabela (ou partição).
-- Mesma informação modelada para DUAS queries diferentes
-- Tabela 1: posts de um autor (query por autor)
CREATE TABLE posts_por_autor (
autor_id UUID,
data TIMESTAMP,
titulo TEXT,
conteudo TEXT,
PRIMARY KEY (autor_id, data)
) WITH CLUSTERING ORDER BY (data DESC);
-- Tabela 2: posts por tag (query por tag)
CREATE TABLE posts_por_tag (
tag TEXT,
data TIMESTAMP,
autor_id UUID,
titulo TEXT,
PRIMARY KEY (tag, data)
) WITH CLUSTERING ORDER BY (data DESC);
-- Os dados são duplicados. Isso é intencional e necessário no Cassandra.
-- Tentar "normalizar" aqui seria um anti-padrão.
Modele suas tabelas a partir das queries, não das entidades. Se uma query nova surgir e não puder ser atendida pelas tabelas existentes, crie uma nova tabela com os dados duplicados. Isso é query-first modeling.
Arquitetura Interna — LSM Tree, Bloom Filters & Tombstones
Cassandra usa LSM Trees (Log-Structured Merge Trees). Escritas → MemTable (RAM) + Commit Log (WAL). Flush → SSTable imutável. Compaction mergeia SSTables, removendo tombstones (marcadores de deleção).
B-Tree é como um índice de enciclopédia: bem organizado, ótimo
para ler, mas cada atualização exige reorganizar páginas no lugar (escrita aleatória,
lenta).
LSM Tree é como um diário de anotações: você sempre escreve
no fim da página atual (RAM/MemTable) e, quando ela enche, arranca a folha e arquiva
como SSTable imutável. Periodicamente, um "bibliotecário" (o processo de
compaction) junta várias folhas antigas, descarta repetições e
deleções (tombstones) e produz folhas novas, ordenadas.
Por que isso favorece a escrita? Toda escrita vira um append
sequencial — o tipo de I/O mais barato em SSD e HDD. Em troca, leitura é mais cara
(pode ter que olhar várias SSTables) e a compaction consome CPU e I/O em background.
Por isso bancos LSM brilham em workloads write-heavy (IoT, logs,
métricas, eventos).
Bloom Filter: estrutura probabilística em RAM que responde rapidamente se uma chave pode existir em uma SSTable (falso positivo possível, falso negativo não). É como um porteiro com lista de convidados aproximada: se ele diz "não está na lista", tem certeza; se diz "talvez esteja", você precisa confirmar entrando. Reduz I/O drasticamente em consultas pontuais.
graph TD
A[Write] --> B[Commit Log]
A --> C[MemTable]
C -->|Flush| D[(SSTable)]
E[Read] --> F[Bloom Filter]
F --> C
F --> D
Casos de Uso Reais
- Netflix: Cassandra para bilhões de eventos de streaming/dia.
- Apple: iCloud — 75.000+ nós gerenciando petabytes.
- Discord: Migrou do Cassandra para ScyllaDB (2022) por problemas de GC da JVM em clusters massivos. Este case é a principal motivação para o ScyllaDB (C++, shard-per-core, latência consistente).
Produtos
| Banco | Licença | Destaque | Limitação |
|---|---|---|---|
| Cassandra | Apache 2.0 | Escala linear, multi-DC | GC pauses, sem JOINs |
| ScyllaDB | AGPL/Enterprise | C++, 10x throughput | Compatibilidade <100% |
| HBase | Apache 2.0 | HDFS nativo | Complexo, depende do Hadoop |
6. Bancos de Grafo — Conceito & Modelo
Modelam dados como nós e arestas, ambos com propriedades. O poder está nas consultas de travessia (traversal) — encontrar caminhos, padrões e conexões indiretas.
// Cypher (Neo4j): estrutura e consulta
CREATE (alice:User {name: 'Alice'})-[:FRIEND {desde: date('2024-01-15')}]->(bob:User {name: 'Bob'});
-- Amigos de amigos (2º grau) que não são amigos diretos
MATCH (eu:User {name: 'Alice'})-[:FRIEND]->(amigo)-[:FRIEND]->(amigo2)
WHERE NOT (eu)-[:FRIEND]->(amigo2) AND eu <> amigo2
RETURN amigo2.name, COUNT(*) AS conexoes LIMIT 10;
Index-Free Adjacency — O Diferencial dos Grafos
O conceito que diferencia bancos de grafo de relacionais é a index-free adjacency.
Em um banco relacional, um JOIN entre usuarios e amizades requer
busca em índice (O log N) para cada hop. Em um banco de grafo nativo, cada nó mantém
ponteiros físicos diretos para seus vizinhos (arestas). Uma travessia de
3 hops no grafo é O(1) por hop — custo constante, independente do tamanho total do banco.
Imagine uma festa:
• Relacional: para descobrir os amigos do João, você abre a lista
de presença (índice), busca "João" (O log N), depois consulta a tabela de amizades.
Para amigos dos amigos, repete tudo. A cada hop, o índice cresce com o número de
pessoas.
• Grafo nativo: o João tem um caderninho no bolso com nomes
e endereços dos amigos. Você vai direto, sem consultar lista nenhuma. Cada hop é uma
consulta direta (O(1)) — não importa se a festa tem 100 ou 100 milhões de pessoas.
Por isso travessias profundas (amigos-de-amigos-de-amigos, detecção de fraude por
caminhos suspeitos, recomendação por similaridade de comunidade) são ordens
de grandeza mais rápidas em bancos de grafo nativos.
Mini-aside sobre complexidade: O log N significa "tempo cresce proporcional ao logaritmo do tamanho dos dados" — buscar em 1 bilhão de registros custa ~30 saltos em uma B-Tree. O(1) significa "tempo constante" — não muda com o tamanho. Para 1 hop a diferença é pequena; para 5 hops em grafo gigante, é a diferença entre milissegundos e minutos.
Supernodes — O Calcanhar de Aquiles
Um supernode é um nó com um número extremamente alto de arestas (ex: uma celebridade com milhões de seguidores). Travessias que passam por supernodes degradam performance drasticamente, pois todas as arestas precisam ser avaliadas. Em produção, é comum modelar supernodes com meta-arestas ou limitar a profundidade da travessia.
Casos de Uso
- LinkedIn: Grafo de conexões profissionais — "pessoas que você talvez conheça".
- PayPal: Detecção de fraude via padrões em grafos de transações.
- NASA: Neo4j para dependências entre componentes de engenharia.
Produtos
| Banco | Licença | Destaque | Limitação Técnica |
|---|---|---|---|
| Neo4j | GPLv3/Enterprise | Cypher, index-free adjacency | Sharding de grafos é complexo (supernodes) |
| ArangoDB | Apache 2.0 | Multi-modelo (grafo+doc+KV) | Performance de travessia inferior a bancos nativos de grafo |
| Amazon Neptune | AWS Proprietário | Managed, Gremlin/SPARQL | Vendor lock-in, custo elevado |
7. Bancos Time-Series — Conceito & Modelo
Otimizados para dados com timestamp. Operações típicas: inserções sequenciais, consultas por intervalo e agregações temporais.
Retention Policies & Continuous Downsampling
Diferentemente de um colunar comum, TSDBs possuem retention policies (ex: deletar dados brutos após 30 dias) e continuous downsampling — agregação automática de dados antigos em resoluções menores (1s → médias de 1min → médias de 1h).
-- Exemplo InfluxDB (Flux simplificado)
from(bucket: "metricas")
|> range(start: -30d)
|> filter(fn: (r) => r._measurement == "cpu")
|> aggregateWindow(every: 1h, fn: mean)
|> yield(name: "cpu_horaria")
Casos de Uso
- Netflix: Atlas (InfluxDB) para 200M+ métricas.
- Uber: M3 para observabilidade de microserviços.
- CERN: InfluxDB para sensores do LHC.
Quando NÃO Usar TSDB
- Atualizações frequentes em registros passados: TSDBs assumem dados imutáveis e append-only. Updates retroativos são caros e, em alguns engines, simplesmente não suportados de forma performática.
- Volumes moderados de dados temporais: Se você tem < 100GB e
poucos milhares de inserções por segundo, PostgreSQL com índice em
created_at+BRINou TimescaleDB resolve com menos complexidade operacional. - Queries relacionais complexas (JOINs): InfluxDB não tem JOIN tradicional. Se sua análise exige cruzar séries com dimensões de negócio complexas, considere ClickHouse ou um data warehouse.
- Alta cardinalidade de tags: InfluxDB (TSM) degrada severamente quando o produto cartesiano de tags ultrapassa milhões de séries únicas. Use Prometheus + Thanos ou ClickHouse nesses casos.
Produtos
| Banco | Licença | Destaque | Limitação |
|---|---|---|---|
| InfluxDB | MIT/Cloud | Flux, TSM engine | Alta cardinalidade de tags |
| TimescaleDB | Apache 2.0/TS | Extensão PG, hypertables | Compressão < InfluxDB |
| Prometheus | Apache 2.0 | Pull model, CNCF | Longo prazo via Thanos/Cortex |
8. Bancos de Search — Conceito & Modelo
Elasticsearch: construído sobre Apache Lucene, usa índices invertidos. Relevância via BM25. Índices em shards.
// Elasticsearch: mapeamento e indexação
PUT /produtos
{ "mappings": { "properties": {
"nome": { "type": "text", "analyzer": "portuguese" },
"preco": { "type": "float" },
"categoria": { "type": "keyword" }
}}}
POST /produtos/_doc
{ "nome": "Fone Bluetooth", "preco": 299.90, "categoria": "áudio" }
Casos de Uso
- Uber: Busca de endereços e geocoding.
- Tinder: Matching geo-espacial.
- Wikipedia: Full-text em milhões de artigos.
Produtos
| Banco | Licença | Destaque | Limitação |
|---|---|---|---|
| Elasticsearch | ELv2/SSPL | ELK, Kibana, ML | RAM, tuning complexo |
| OpenSearch | Apache 2.0 | Fork AWS compatível | Comunidade consolidando |
| Meilisearch | MIT | Leve, typo-tolerant | Menos features |
9. Bancos Vetoriais — Conceito & Embeddings
Armazenam e indexam vetores densos (embeddings) de 300 a 4096 dimensões. Algoritmo dominante: HNSW — grafo em múltiplas camadas, busca O(log N) aproximada.
# Embedding + upsert no Pinecone
from openai import OpenAI
from pinecone import Pinecone
emb = OpenAI().embeddings.create(
model="text-embedding-3-large",
input="Fone Bluetooth com cancelamento de ruído"
).data[0].embedding
Pinecone().Index("produtos").upsert(
vectors=[("prod-789", emb, {"nome": "Fone Bluetooth Pro"})]
)
RAG & IA Generativa
Retrieval-Augmented Generation: chunking → embedding → armazenamento → busca dos K chunks mais similares → injeção no prompt do LLM.
graph LR
A[Documentos] --> B[Chunking]
B --> C[Embedding]
C --> D[(Banco Vetorial)]
E[Pergunta] --> F[Embedding]
F --> D
D --> G[Top-K Chunks]
G --> H[Prompt]
H --> I[LLM]
I --> J[Resposta]
Hybrid Search — O Estado da Arte em 2026
Ninguém usa apenas busca vetorial pura em produção. O padrão moderno é hybrid search: combinar resultados de busca vetorial (similaridade semântica) com busca lexical (BM25 / texto pleno) e fundi-los via Reciprocal Rank Fusion (RRF) ou pesos ajustados (weighted scoring).
graph TD
A[Query do Usuário] --> B[Embedding da Query]
A --> C[Análise Lexical]
B --> D[Índice HNSW]
C --> E[Índice Invertido BM25]
D --> F[Top-K Vetorial]
E --> G[Top-K Lexical]
F --> H[Fusão RRF]
G --> H
H --> I[Resultado Final Ranqueado]
Bancos como Weaviate e Elasticsearch (8.x+) oferecem hybrid search nativo. O Pinecone recentemente adicionou suporte a sparse vectors para permitir a mesma fusão. Essa combinação captura tanto a intenção semântica quanto a precisão de palavras-chave exatas.
Quando NÃO Usar Banco Vetorial
- Volume pequeno (< 1M vetores): Um índice
pgvectorHNSW em PostgreSQL resolve sem custo extra de SaaS dedicado. Pinecone só compensa em escala. - Busca exata por palavra-chave: Para "encontrar produto cujo SKU é
ABC-123", índice invertido (Elasticsearch) ou simples B-Tree são ordens de grandeza mais rápidos e baratos. Vetorial é para significado, não literal. - Filtros complexos como critério primário: Se 90% das queries filtram por país + categoria + preço e só 10% precisam de similaridade, o vetorial vira gargalo. Use SQL com filtros + reranking por similaridade no final.
- Dados que mudam toda hora: Re-embedding em massa é caro (latência + custo do modelo). Vetorial brilha em corpora relativamente estáveis (docs, catálogo, base de conhecimento).
- Substituir banco transacional: Vetorial não tem ACID, não é fonte de verdade. Mantenha PG/Mongo como master e o vetorial como índice secundário (igual ao papel do Elasticsearch).
Produtos
| Banco | Licença | Índice | Hybrid Search | Limitação |
|---|---|---|---|---|
| Pinecone | SaaS | HNSW+PQ | Sparse vectors (beta) | Lock-in, custo |
| Weaviate | BSD-3 | HNSW | Nativo (BM25+vetor) | Self-hosted requer tuning |
| Qdrant | Apache 2.0 | HNSW | Filtros + vetor | Ecossistema novo |
| pgvector | MIT | IVFFlat/HNSW | Via SQL + tsvector | Menos otimizado |
São alternativas, não complementares. Use Pinecone/Weaviate se precisar de hybrid search avançado. Use pgvector se já estiver no ecossistema PostgreSQL e quiser evitar sincronização de dois bancos.
Tabela Comparativa Geral
Agora com duas colunas extras para apoiar decisões de mundo real:
💰 Custo Relativo (TCO típico em escala média —
$ barato, $$$$ caro) e
🛠️ Carga Operacional (esforço de setup + manutenção em produção).
| Família | Modelo | Consistência | Escala | Latência | 💰 Custo | 🛠️ Op. Burden | Principal |
|---|---|---|---|---|---|---|---|
| Relacional | Tabelas | ACID | Vertical (+ shard) | 1-10ms | $$ | Baixo (managed) / Médio (self) | PostgreSQL |
| Colunar/OLAP | Colunas | Eventual | Horizontal massiva | 100ms-10s | $$$ (BigQuery) / $ (DuckDB) | Médio | ClickHouse |
| Documento | JSON | Tunable | Horizontal | 1-10ms | $$$ (Atlas) | Médio (replica set + shard) | MongoDB |
| Key-Value | KV | Eventual/Forte | Horizontal | <1ms | $$$$ (RAM!) | Baixo (Redis), Zero (DynamoDB) | Redis |
| Wide-Column | Rows+Cols | Eventual | Horizontal linear | 1-5ms | $$ | Alto (clusters, GC, compaction) | Cassandra |
| Grafo | Nós+Arestas | ACID | Vertical (+ shard) | 5-50ms | $$$ (Enterprise) | Médio-Alto (sharding complexo) | Neo4j |
| Time-Series | Timestamp | Eventual | Horizontal | 1-10ms | $$ | Médio (retention, downsampling) | InfluxDB |
| Search | Índice Invertido | Eventual | Horizontal | 10-100ms | $$$ (RAM + disco) | Alto (tuning de mapping/analyzer) | Elasticsearch |
| Vetorial | Vetores | Eventual | Horizontal | 5-50ms | $$$$ (SaaS) / $$ (self) | Baixo (SaaS), Médio (self) | Pinecone |
Escolher Cassandra ou Neo4j para um MVP com 2 devs e 3 semanas de prazo é o tipo de decisão que afunda o produto antes dele validar mercado. Comece com PostgreSQL + Redis em quase todos os casos — eles cobrem ~80% dos cenários até centenas de milhares de usuários, com carga operacional baixa. Migre para soluções especializadas só quando a dor for real e mensurável.
Glossário Para o Trainee
Os termos mais densos do material, explicados sem usar mais jargão. Use como referência rápida ao ler outras seções.
| Termo | O que é (em uma frase) | Analogia | Onde aparece |
|---|---|---|---|
| ACID | Garantias de transação: Atomicidade, Consistência, Isolamento, Durabilidade. | Caixa eletrônico que ou completa a transferência inteira, ou não tira nada da sua conta. | Relacional, MongoDB 4+ |
| BASE | Basically Available, Soft state, Eventual consistency — alternativa relaxada ao ACID. | Curtida no Instagram: pode aparecer agora ou em 200ms; o sistema converge. | NoSQL, Cassandra |
| CAP | Em uma partição de rede, você escolhe entre Consistência ou Disponibilidade. | Telefone cortado: ou você confia na última info que ouviu (A), ou desliga e pede para repetir (C). | Sistemas distribuídos |
| PACELC | Extensão do CAP: mesmo SEM partição, troca latência (L) por consistência (C). | Drive-thru: confirmar pedido com gerente (consistência) vs. já entregar (latência). | Modelos distribuídos modernos |
| WAL | Write-Ahead Log: registrar a operação em um log antes de aplicar nos dados. | Comanda do garçom: anota antes de mexer no caixa. | PostgreSQL, Cassandra, SQLite |
| MVCC | Multi-Version Concurrency Control: cada transação vê seu snapshot, leituras não bloqueiam escritas. | Google Docs com histórico — cada um vê sua revisão consistente. | PostgreSQL, MongoDB, Oracle |
| B-Tree | Árvore balanceada de busca, ótima para leitura ordenada e por chave. | Índice remissivo de enciclopédia. | Quase todo banco relacional |
| LSM Tree | Log-Structured Merge — escreve sempre no fim (rápido), depois mergeia em background. | Diário de anotações: você sempre escreve na última página. | Cassandra, RocksDB, ScyllaDB |
| SSTable | Sorted String Table: arquivo imutável e ordenado gerado pelo flush da MemTable. | Página arquivada do diário — não muda mais, fica catalogada. | LSM-based DBs |
| Tombstone | Marcador de deleção em LSM — o registro continua até a compaction limpá-lo. | Post-it "EXCLUÍDO" colado em cima de uma anotação no diário. | Cassandra, ScyllaDB |
| Compaction | Processo de mesclar SSTables, removendo duplicatas e tombstones. | Bibliotecário juntando folhas antigas e refazendo a organização. | LSM-based DBs |
| Bloom Filter | Estrutura em RAM que diz "talvez exista" ou "definitivamente não existe". | Porteiro com lista aproximada de convidados. | Cassandra, HBase |
| Sharding | Dividir os dados em pedaços (shards) hospedados em máquinas diferentes. | Lista telefônica dividida por inicial da letra entre 26 prédios. | Sistemas distribuídos |
| Hashed Sharding | Aplicar hash na chave para distribuir uniformemente. | Fila do banco: senha aleatória sorteada, não por ordem de chegada. | MongoDB, DynamoDB |
| Cardinalidade | Quantos valores distintos uma coluna/tag tem. | Coluna "país" tem cardinalidade baixa (~200); coluna "user_id" tem altíssima. | Índices, TSDBs |
| Index-Free Adjacency | Cada nó já guarda ponteiro físico para os vizinhos — sem precisar de índice. | Caderninho de telefone no bolso vs. consultar a lista telefônica toda vez. | Neo4j, grafos nativos |
| Supernode | Nó com altíssimo grau (milhões de arestas) — gargalo em travessias. | Cristiano Ronaldo no Instagram: ninguém quer iterar pelos 600M seguidores. | Grafos sociais |
| O(log N) | Tempo cresce muito devagar com o tamanho — 1 bilhão = ~30 saltos. | Subir escada onde cada degrau dobra a área coberta. | B-Tree, HNSW |
| O(1) | Tempo constante — não importa o tamanho dos dados. | Pegar a chave do bolso, sempre o mesmo gesto. | Hash table, grafo nativo (por hop) |
| HNSW | Hierarchical Navigable Small World: grafo em camadas para busca vetorial aproximada. | Atlas com mapas em zoom — começa no mundo, desce até o bairro. | Pinecone, Weaviate, pgvector |
| Embedding | Vetor numérico que representa o "significado" de um texto/imagem. | Coordenadas no mapa cultural — "rei" e "rainha" ficam pertinho. | RAG, busca semântica |
| BM25 | Algoritmo clássico de relevância em busca por palavra-chave. | Score do Google antiga escola: importa frequência + raridade do termo. | Elasticsearch, Lucene |
| RRF | Reciprocal Rank Fusion: combinar rankings de fontes diferentes em um único. | Soma dos lugares no pódio — quem ficou bem em várias provas, vence. | Hybrid search |
| OLTP | Online Transaction Processing — muitas operações pequenas (CRUD). | Caixa do supermercado: muitas transações curtas. | PostgreSQL, MySQL |
| OLAP | Online Analytical Processing — poucas queries enormes (agregações). | Relatório de fim de mês: lê milhões, escreve um número. | ClickHouse, BigQuery |
| Quorum / Majority | Confirmação por mais da metade dos nós da réplica. | Votação no condomínio — só passa com maioria. | Cassandra, MongoDB |
Teorema PACELC — Indo Além do CAP
O CAP Theorem só fala sobre o que acontece durante uma partição de rede. Mas, na prática, a maior parte do tempo o sistema não está particionado — e mesmo assim precisa decidir entre latência e consistência. É aí que entra o PACELC, proposto por Daniel Abadi (2010):
Partition? Então escolha entre Availability e
Consistency (clássico CAP).
Else (sem partição), escolha entre Latency e
Consistency.
| Sistema | Durante partição | Sem partição | Classificação PACELC |
|---|---|---|---|
| PostgreSQL (single) | N/A (não distribuído) | Prefere consistência | — |
| MongoDB (default) | Mantém consistência (CP) | Prefere consistência | PC/EC |
| Cassandra | Mantém disponibilidade (AP) | Prefere latência | PA/EL |
| DynamoDB (eventual) | AP | Prefere latência | PA/EL |
| DynamoDB (strong) | CP | Prefere consistência | PC/EC |
| CockroachDB | CP | Prefere consistência | PC/EC |
Quando você lê documentação de banco distribuído, atenção ao "E": é ali que se decide se sua leitura vai retornar em 2ms (eventual, replicada local) ou em 20ms (lendo quorum global). Partição é raro; latência é todo dia. O PACELC obriga o arquiteto a pensar nos dois cenários.
Erros Comuns na Escolha de Banco
Tentar normalizar dados no Cassandra (criar tabelas como se fosse PostgreSQL) é o erro mais comum. Cassandra exige query-first modeling: duplique dados, crie uma tabela para cada query. JOINs não existem.
ES é índice secundário. Risco de perda de dados em split-brain é real. Mantenha a fonte primária em outro banco.
ObjectId/timestamp como shard key sem hashed sharding = hot shard. Sempre avalie se a chave é monotônica.
Tendências 2026
- Hybrid Search como padrão: BM25 + vetor via RRF. Weaviate, ES e Pinecone competem nesse espaço.
- Serverless databases: Neon (PG), Planetscale (MySQL), DynamoDB.
- DuckDB: "SQLite para analytics" — análise local em Parquet/CSV/JSON.
- NewSQL em ascensão: CockroachDB, YugabyteDB — PostgreSQL wire-compatible com consistência distribuída nativa (CP).
- FinOps em bancos vetoriais: Custo de transferência de dados em SaaS (Pinecone) vs self-hosted (pgvector/Qdrant) é fator de decisão crescente.