Por que o NoSQL existe?
Os bancos de dados relacionais (SQL) são excelentes para dados estruturados
com relações claras e garantias ACID fortes. Mas quando uma aplicação cresce
para uma escala enorme (milhões de usuários, dados muito heterogêneos ou de
estrutura mutável), o modelo rígido de tabelas e os JOIN podem se tornar
um gargalo.
NoSQL ("not only SQL") agrupa bancos de dados que abrem mão de parte do
modelo relacional (esquema fixo, JOIN, ACID estrito) em troca de
flexibilidade e escalabilidade horizontal. Não é "melhor" que SQL: é uma
ferramenta diferente para problemas diferentes.
As quatro famílias NoSQL
1. Documentos (MongoDB, CouchDB)
Guardam documentos tipo JSON, com estrutura flexível. Cada documento pode ter campos distintos. Ideal quando os dados são aninhados ou o esquema evolui.
// Um documento no MongoDB
{
_id: "u123",
nome: "Ada",
enderecos: [ { cidade: "Madri" }, { cidade: "Londres" } ]
}
2. Chave-valor (Redis, DynamoDB)
O modelo mais simples: um dicionário gigante chave → valor. Acesso
ultrarrápido por chave. Perfeito para caches, sessões e contadores.
SET sessao:ab12 "{usuario: 'Ada'}"
GET sessao:ab12
3. Grafos (Neo4j)
Modelam nós e relações como cidadãos de primeira classe. Brilham quando o importante são as conexões: redes sociais ("amigos de amigos"), recomendações, detecção de fraude.
4. Colunar / família de colunas (Cassandra, HBase)
Armazenam os dados por colunas em vez de por linhas. Otimizadas para escritas massivas e consultas analíticas sobre conjuntos enormes (big data).
SQL vs NoSQL: quando usar cada um
| SQL (relacional) | NoSQL | |
|---|---|---|
| Esquema | fixo, definido com antecedência | flexível ou sem esquema |
| Relações | JOIN nativo |
desnormalização / aninhado |
| Garantias | ACID forte | muitas vezes eventual consistency |
| Escalabilidade | vertical (máquina mais potente) | horizontal (mais máquinas) |
| Quando | dados relacionados, integridade crítica (banco, ERP) | escala massiva, dados flexíveis, alta disponibilidade |
O teorema CAP
O teorema CAP (Brewer) descreve um limite fundamental dos sistemas distribuídos (dados repartidos em vários nós). Diante de uma falha de rede, você só pode garantir duas dessas três propriedades:
- C — Consistência (Consistency). Toda leitura devolve o dado mais recente; todos os nós veem a mesma coisa.
- A — Disponibilidade (Availability). Toda requisição recebe uma resposta (sem erros), ainda que não seja o dado mais novo.
- P — Tolerância a partições (Partition tolerance). O sistema continua funcionando mesmo que a rede entre os nós se corte.
A chave: em um sistema distribuído real, as partições de rede ocorrem, então P é obrigatória. A escolha real é entre CP e AP:
- CP (consistência + tolerância a partições): diante de um corte, prefere rejeitar requisições a devolver dados velhos. Ex.: bancos.
- AP (disponibilidade + tolerância a partições): diante de um corte, responde mesmo assim ainda que o dado possa estar um pouco desatualizado (eventual consistency). Ex.: feeds de redes sociais, carrinhos de compra.
CAP não diz "escolha 2 de 3 livremente": na prática P vem imposta, e você decide entre consistência e disponibilidade quando há partição.
Escalabilidade: replicação e sharding
Para suportar mais carga e dados há duas estratégias complementares:
Replicação
Manter cópias dos mesmos dados em vários servidores.
- Melhora a disponibilidade (se um nó cai, outro responde) e a leitura (você reparte as consultas entre as réplicas).
- Padrão comum primário-réplica: as escritas vão para o primário e são propagadas às réplicas (que servem leituras).
Sharding (particionamento horizontal)
Repartir os dados entre vários servidores: cada shard guarda um subconjunto das linhas (p. ex. usuários A–M no shard 1, N–Z no shard 2), conforme uma chave de particionamento (shard key).
- Melhora a escrita e a capacidade: nenhuma máquina guarda tudo.
- Mais complexo: as consultas que cruzam shards e manter o equilíbrio entre eles são difíceis. Escolher bem a shard key é crítico.
Resumo: a replicação copia os mesmos dados (alta disponibilidade e leituras); o sharding reparte dados diferentes (escala escrita e volume). Em grande escala se combinam: cada shard, além disso, replicado.
Exemplos
Documento JSON (estilo MongoDB)
// No NoSQL de documentos não há tabelas fixas:
const usuario = {
_id: "u42",
nome: "Grace",
pedidos: [
{ id: 1, total: 120 },
{ id: 8, total: 150 },
],
};
console.log(usuario.pedidos.length); // 2