SQL vs NoSQL: As Diferenças Explicadas e Quando Utilizar Cada Uma em 2026
✎ Duarte Spínola | 2026-07-14
A escolha entre SQL e NoSQL é uma das decisões mais importantes na arquitectura de qualquer aplicação. SQL (bases de dados relacionais) existe desde 1970 e é maduro, normalizado e transaccional. NoSQL (não-relacionais) surgiu nos anos 2000 para responder a necessidades de escala, flexibilidade de schema e volumes de dados que o SQL não resolvia bem. A escolha errada causa problemas de performance, consistência e manutenção que nenhuma optimização resolve. Este artigo explica as diferenças fundamentais entre os dois paradigmas, os modelos de dados de cada tipo, e quando utilizar cada um com exemplos práticos. Referência: SQL — Wikipedia e NoSQL — Wikipedia.
Não existe “melhor” paradigma. Existe o paradigma correcto para um cenário. Aplicações financeiras precisam de SQL (ACID, consistência forte). Aplicações de rede social, IoT e catálogos flexíveis beneficiam de NoSQL (disponibilidade, schema flexível, escala horizontal). Muitas aplicações modernas usam ambos — SQL para dados transaccionais e NoSQL para cache, busca ou dados semi-estruturados.
1. O Que é SQL (Bases de Dados Relacionais)
SQL (Structured Query Language) é a linguagem para gerir bases de dados relacionais. Os dados são organizados em tabelas com linhas (registos) e colunas (campos), com relações entre tabelas via chaves primárias (PK) e chaves estrangeiras (FK).
Características do SQL
| Característica | Descrição |
|---|---|
| Estrutura | Tabelas com schema rígido — cada coluna tem tipo definido (INT, VARCHAR, DATE, BOOLEAN) |
| Schema | Estático — definido antes de inserir dados. Alterar schema requer migration |
| Relações | JOINs entre tabelas via chaves estrangeiras (1:1, 1:N, N:M) |
| Transacções | ACID — Atomicidade, Consistência, Isolamento, Durabilidade |
| Queries | Linguagem SQL declarativa (SELECT, INSERT, UPDATE, DELETE, JOIN, GROUP BY) |
| Escala | Primariamente vertical (mais CPU/RAM no mesmo servidor). Replicação para leitura |
| Consistência | Forte — leitura sempre devolve o dado mais recente |
| Exemplos | PostgreSQL, MySQL, SQLite, Oracle, SQL Server, MariaDB |
Exemplo de modelo relacional
CREATE TABLE clientes (
id SERIAL PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE pedidos (
id SERIAL PRIMARY KEY,
cliente_id INT REFERENCES clientes(id),
total DECIMAL(10,2) NOT NULL,
data_pedido TIMESTAMP DEFAULT NOW()
);
CREATE TABLE itens_pedido (
id SERIAL PRIMARY KEY,
pedido_id INT REFERENCES pedidos(id),
produto VARCHAR(200) NOT NULL,
quantidade INT NOT NULL,
preco_unitario DECIMAL(10,2) NOT NULL
);
— Query com JOIN: todos os pedidos de um cliente
SELECT c.nome, p.data_pedido, p.total
FROM clientes c
JOIN pedidos p ON p.cliente_id = c.id
WHERE c.email = ‘[email protected]’
ORDER BY p.data_pedido DESC;
Referência: PostgreSQL — Tutorial.
2. O Que é NoSQL (Bases de Dados Não-Relacionais)
NoSQL (Not Only SQL) agrupa bases de dados que não usam o modelo relacional de tabelas. Surgiram para responder a três necessidades: escala horizontal (distribuir dados por múltiplos servidores), schema flexível (dados sem estrutura rígida) e volumes massivos (big data, IoT, tempo real).
Características do NoSQL
| Característica | Descrição |
|---|---|
| Estrutura | Varia por tipo: documentos (JSON), chave-valor, colunas, grafos |
| Schema | Flexível — cada registo pode ter campos diferentes. Sem migrations |
| Relações | Limitadas — NoSQL não foi desenhado para JOINs complexos |
| Transacções | BASE — Basically Available, Soft state, Eventually consistent (alguns suportam ACID) |
| Queries | API específica de cada banco (MongoDB query language, Redis commands, CQL) |
| Escala | Horizontal por defeito — distribuir por múltiplos nós (sharding) |
| Consistência | Eventual por defeito — pode haver leituras desactualizadas temporariamente |
| Exemplos | MongoDB, Redis, Cassandra, DynamoDB, Neo4j, Elasticsearch |
Tipos de bases de dados NoSQL
| Tipo | Modelo | Exemplos | Quando usar |
|---|---|---|---|
| Documento | JSON/BSON, schema flexível | MongoDB, Couchbase, CouchDB | Catálogos, CMS, dados semi-estruturados |
| Chave-Valor | Chave única mapeada a valor | Redis, DynamoDB, Memcached | Cache, sessões, contadores, baixa latência |
| Colunar | Dados em colunas distribuídas | Cassandra, HBase, ClickHouse | Escritas massivas, dados temporais, multi-datacenter |
| Gráfico | Nós e relações (arestas) | Neo4j, Amazon Neptune | Recomendações, fraud detection, redes sociais |
| Search | Índice invertido full-text | Elasticsearch, Meilisearch, Typesense | Busca textual, logs, analytics |
| Time-series | Dados temporais optimizados | InfluxDB, TimescaleDB, Prometheus | IoT, métricas, monitorização |
Referência: MongoDB — Documentos.
3. Diferenças Fundamentais: SQL vs NoSQL
Tabela comparativa completa
| Critério | SQL | NoSQL |
|---|---|---|
| Modelo de dados | Tabelas relacionais com schema rígido | Documentos, chave-valor, colunas, grafos — schema flexível |
| Schema | Estático — definido à priori. Mudanças requerem migration | Dinâmico — adicionar campos é automático, sem migration |
| Relações | JOINs nativos (1:1, 1:N, N:M) | Relações limitadas ou inexistentes. Dados desnormalizados |
| Transacções | ACID garantido em todas as operações | BASE por defeito. Alguns suportam ACID (MongoDB 4.0+, Cassandra LWT) |
| Consistência | Forte — leitura sempre actualizada | Eventual — leitura pode estar desactualizada temporariamente |
| Escalabilidade | Vertical (mais hardware no mesmo nó). Replicação para leitura | Horizontal (sharding por múltiplos nós). Auto-sharding em alguns |
| Queries | SQL padrão — declarativa, rica, madura | API própria de cada banco. Menos expressiva para queries complexas |
| JOINs | Eficientes e optimizados | Evitados — dados desnormalizados ou múltiplas queries |
| Normalização | Recomendada (evitar redundância) | Desnormalização intencional (evitar JOINs) |
| Migrations | Obrigatórias e podem ser complexas | Inexistentes — schema evolui naturalmente |
| Maturidade | 50+ anos, ecossistema maduro, ferramentas abundantes | 15-20 anos, ecossistema em evolução |
| Comunidade | Enorme — DBAs, ORM, ferramentas, formação | Crescente — devops-oriented, cloud-native |
| Custo | Open-source (PostgreSQL, MySQL) ou licenciado (Oracle, SQL Server) | Open-source (MongoDB, Redis) ou gerido cloud (DynamoDB, CosmosDB) |
Schema: rígido vs flexível
CREATE TABLE produtos (
id SERIAL PRIMARY KEY,
nome VARCHAR(200) NOT NULL,
preco DECIMAL(10,2) NOT NULL,
categoria VARCHAR(50)
);
— Para adicionar um campo novo: ALTER TABLE produtos ADD COLUMN peso DECIMAL(5,2);
— Migration necessária — pode bloquear a tabela em grandes volumes
db.produtos.insertOne({ nome: “Portátil”, preco: 999.99, categoria: “informática” });
db.produtos.insertOne({ nome: “Cadeira”, preco: 199.50, categoria: “mobiliário”, cor: “preta”, peso: 12.5 });
db.produtos.insertOne({ nome: “Software”, preco: 49.99, tipo: “licença”, duracao_meses: 12 });
// Sem migration — cada documento tem a estrutura que precisa
Normalização vs Desnormalização
— Tabela “clientes” + Tabela “pedidos” + Tabela “itens_pedido”
— Para obter um pedido completo: JOIN de 3 tabelas
SELECT c.nome, p.data_pedido, i.produto, i.quantidade, i.preco_unitario
FROM clientes c
JOIN pedidos p ON p.cliente_id = c.id
JOIN itens_pedido i ON i.pedido_id = p.id
WHERE p.id = 12345;
db.pedidos.insertOne({
_id: 12345,
cliente: { nome: “Duarte Freitas”, email: “[email protected]” },
data_pedido: “2026-07-14”,
itens: [
{ produto: “Portátil”, quantidade: 1, preco_unitario: 999.99 },
{ produto: “Rato”, quantidade: 2, preco_unitario: 15.00 }
],
total: 1029.99
});
// Uma única query devolve tudo — sem JOINs
db.pedidos.findOne({ _id: 12345 });
4. ACID vs BASE: Consistência
ACID (SQL)
ACID é o modelo de transacções das bases de dados relacionais. Garante que as operações são fiáveis mesmo em caso de falhas.
| Propriedade | Significado | Exemplo |
|---|---|---|
| Atomicidade | Tudo ou nada — se uma parte da transacção falha, toda a transacção é revertida | Transferência bancária: débito + crédito devem ambos succeeds ou ambos falham |
| Consistência | A base de dados passa de um estado válido para outro válido. Constraints são verificadas | Saldo não pode ser negativo se a constraint CHECK o impede |
| Isolamento | Transacções concorrentes não interferem entre si | Dois utilizadores a transferir do mesmo saldo não causam race condition |
| Durabilidade | Após commit, a transacção persiste mesmo em caso de falha de energia | Após “COMMIT”, o dado está em disco |
Referência: ACID — Wikipedia.
BASE (NoSQL)
BASE é o modelo das bases de dados NoSQL distribuídas. Prioriza disponibilidade sobre consistência imediata.
| Propriedade | Significado | Exemplo |
|---|---|---|
| Basically Available | O sistema está sempre disponível, mesmo com partições de rede | Mesmo que um nó caia, o sistema responde com os dados disponíveis |
| Soft state | O estado pode mudar sem input directo (convergência automática) | Réplicas convergem para o mesmo valor ao longo do tempo |
| Eventually consistent | Com tempo, todas as réplicas convergem para o mesmo valor | Um like numa rede social pode demorar segundos a aparecer em todas as regiões |
Quando ACID é indispensável
- Transacções financeiras (transferências, pagamentos)
- Sistemas de reservas (bilhetes, hotel — não pode vender o mesmo lugar duas vezes)
- Inventário (stock não pode ir abaixo de zero)
- Registos médicos (dados têm de ser exactos)
Quando BASE é aceitável
- Feeds de rede social (um like pode demorar a propagar)
- Contadores de visualizações (exactidão absoluta não é crítica)
- Logs e eventos (ordem não é estritamente necessária)
- Recomendações (aproximação é suficiente)
5. Teorema CAP: A Escolha Inevitável
O teorema CAP estabelece que um sistema distribuído pode garantir no máximo duas de três propriedades:
| Propriedade | Descrição |
|---|---|
| Consistência | Todas as leituras recebem a escrita mais recente ou um erro |
| Disponibilidade | Todo o pedido recebe uma resposta (não necessariamente a mais recente) |
| Tolerância a Partição | O sistema funciona apesar de falhas de rede entre nós |
Como partições de rede são inevitáveis, a escolha real é:
| Escolha | Tipo | Bancos | Priorizam |
|---|---|---|---|
| CP | Consistência + Partição | PostgreSQL (single-node), CockroachDB, MongoDB (majority) | Consistência — bloqueia se não sincronizar |
| AP | Disponibilidade + Partição | Cassandra, DynamoDB, Couchbase | Disponibilidade — responde mesmo com dados desactualizados |
| CA | Consistência + Disponibilidade | PostgreSQL (single-node), SQLite | Funciona sem partições — não distribuído |
Bancos SQL single-node (PostgreSQL, SQLite) são CA — garantem consistência e disponibilidade mas não são distribuídos. Bancos NoSQL distribuídos (Cassandra, DynamoDB) são AP — garantem disponibilidade mas permitem consistência eventual. Bancos NewSQL (CockroachDB, Spanner) são CP — garantem consistência forte distribuída, mas com maior latência.
Referência: Teorema CAP — Wikipedia.
6. Escalabilidade: Vertical vs Horizontal
SQL — Escala Vertical
– Mais CPU (8 cores -> 16 cores -> 32 cores)
– Mais RAM (64GB -> 128GB -> 256GB)
– SSD mais rápido (SATA -> NVMe -> NVMe Gen5)
Limitações:
– Custo cresce exponencialmente acima de certo ponto
– Hardware tem limite físico
– downtime para upgrade
Replicação:
– 1 primary (escrita) + N replicas (leitura)
– Escala leituras mas não escritas
– Lag de replicação pode afectar consistência
NoSQL — Escala Horizontal
Cassandra:
– Dados distribuídos por partition key (consistent hashing)
– Adicionar nós = mais capacidade de escrita E leitura
– Sem master — todos os nós são iguais
– Linear scalability: 2x nós = 2x throughput
MongoDB:
– Sharding por shard key
– mongos router distribui queries
– Cada shard é um replica set
– Escala escritas e leituras
Redis Cluster:
– 16384 slots distribuídos por nós
– Hash slot = CRC16(key) % 16384
– Cada nó responsável por um range de slots
| Critério | SQL (vertical) | NoSQL (horizontal) |
|---|---|---|
| Custo | Exponencial acima de certo ponto | Linear — adicionar servidores commodity |
| Limite | Hardware máximo de um servidor | Praticamente ilimitado |
| Complexidade | Baixa — um servidor | Alta — sharding, replicação, consistência |
| Downtime | Sim para upgrade de hardware | Não — adicionar nós sem parar |
| Escrita | Limitada ao master | Distribuída por múltiplos nós |
| Leitura | Réplicas (com lag) | Distribuída por múltiplos nós |
7. Exemplos Práticos por Tipo de NoSQL
Documento — MongoDB
db.produtos.insertMany([
{ nome: “Portátil HP”, preco: 899.99, specs: { cpu: “i7”, ram: “16GB”, ssd: “512GB” } },
{ nome: “Monitor Dell”, preco: 249.00, specs: { tamanho: “27\””, resolução: “2560×1440”, refresh: “144Hz” } },
{ nome: “Licença Office”, preco: 149.00, tipo: “digital”, duracao_meses: 12 }
]);
// Query por campo aninhado
db.produtos.find({ “specs.cpu”: “i7” });
db.produtos.find({ “specs.refresh”: “144Hz” });
Referência: MongoDB — Documentos.
Chave-Valor — Redis
SET session:user:123 ‘{“user_id”:123,”name”:”Duarte”,”role”:”admin”}’ EX 1800
GET session:user:123
# Contador atómico (rate limiting)
INCR api:requests:user:123:20260714
EXPIRE api:requests:user:123:20260714 86400
# Sorted set (leaderboard)
ZADD ranking:semanal 1500 “user:123” 2300 “user:456” 980 “user:789”
ZREVRANGE ranking:semanal 0 2 WITHSCORES
Referência: Redis — Getting Started.
Colunar — Cassandra
CREATE TABLE timeline (
user_id UUID,
created_at TIMESTAMP,
sender_id UUID,
content TEXT,
PRIMARY KEY ((user_id), created_at)
) WITH CLUSTERING ORDER BY (created_at DESC);
— Escrita rápida (sem leitura prévia)
INSERT INTO timeline (user_id, created_at, sender_id, content)
VALUES (550e8400-e29b-41d4-a716-446655440000, now(), 660e…, ‘Olá!’);
— Leitura eficiente (uma partição)
SELECT * FROM timeline
WHERE user_id = 550e8400-e29b-41d4-a716-446655440000
ORDER BY created_at DESC LIMIT 50;
Referência: Cassandra — Data Modeling.
Gráfico — Neo4j
// Encontrar amigos de amigos que ainda não são amigos
MATCH (me:User {name: “Duarte”})-[:FRIENDS_WITH]->(friend)
-[:FRIENDS_WITH]->(foaf)
WHERE NOT (me)-[:FRIENDS_WITH]->(foaf)
AND me <> foaf
RETURN foaf.name AS recommendation, count(friend) AS friends_in_common
ORDER BY friends_in_common DESC LIMIT 5;
// Fraud detection: ciclo de transacções suspeitas
MATCH path = (a:Account)-[:TRANSFERRED_TO*2..4]->(a)
WHERE ALL(r IN relationships(path) WHERE r.amount > 10000)
RETURN path;
Referência: Neo4j — Getting Started.
Search — Elasticsearch
POST /artigos/_search
{
“query”: {
“multi_match”: {
“query”: “diagnóstico rede lentidão”,
“fields”: [“titulo^3”, “conteudo^1”, “tags^2”],
“type”: “best_fields”,
“fuzziness”: “AUTO”
}
},
“highlight”: {
“fields”: {
“conteudo”: { “pre_tags”: [“<mark>”], “post_tags”: [“</mark>”] }
}
}
}
Referência: Elasticsearch — Introduction.
8. Quando Utilizar SQL
Cenários onde SQL é a escolha correcta
| Cenário | Porquê | Bancos recomendados |
|---|---|---|
| Aplicação financeira | ACID, transacções multi-tabela, consistência forte | PostgreSQL, CockroachDB |
| ERP / CRM | Dados estruturados, relações complexas, relatórios | PostgreSQL, SQL Server |
| SaaS multi-tenant | Row-level security, esquemas isolados, queries complexas | PostgreSQL |
| E-commerce transaccional | Pedidos, pagamentos, stock — ACID obrigatório | PostgreSQL, MySQL |
| Sistema com relações complexas | JOINs multi-nível, constraints, integridade referencial | PostgreSQL, SQLite (small) |
| Aplicação com schema estável | Schema bem definido que raramente muda | PostgreSQL, MySQL |
| Data warehouse / BI | Queries analíticas, agregações, OLAP | PostgreSQL, ClickHouse |
| Aplicação que precisa de reporting | SQL é expressivo para relatórios complexos | PostgreSQL, SQL Server |
Vantagens do SQL
- Transacções ACID — garantia de integridade
- SQL padrão — linguagem madura, amplamente conhecida
- JOINs eficientes — relacionar dados de múltiplas tabelas
- Constraints — integridade referencial, checks, unique
- Ecossistema — ORMs, ferramentas BI, DBAs, formação
- Maturidade — 50+ anos de evolução e optimização
9. Quando Utilizar NoSQL
Cenários onde NoSQL é a escolha correcta
| Cenário | Porquê | Bancos recomendados |
|---|---|---|
| Catálogo com atributos variáveis | Schema flexível — cada produto tem atributos diferentes | MongoDB, Couchbase |
| Cache e sessões | Baixa latência (< 1ms), TTL automático | Redis, DynamoDB |
| IoT / telemetria | Escritas massivas distribuídas, dados temporais | Cassandra, InfluxDB |
| Feed / timeline | Escrita rápida, leitura por partition key, AP | Cassandra, DynamoDB |
| Recomendações / relações | Grafos de relações complexas | Neo4j, Amazon Neptune |
| Busca full-text | Índice invertido, relevância, facets | Elasticsearch, Meilisearch |
| Logs / eventos | Volume massivo, schema flexível, busca | Elasticsearch, ClickHouse |
| Aplicação com iteracção rápida | Schema evolui constantemente, sem migrations | MongoDB |
| Sistema multi-região | Disponibilidade em múltiplas regiões, baixa latência local | Cassandra, DynamoDB |
Vantagens do NoSQL
- Schema flexível — sem migrations, adapta-se a dados variáveis
- Escala horizontal — adicionar nós commodity, sem limite físico
- Performance — optimizado para padrões de acesso específicos
- Disponibilidade — AP no teorema CAP, sempre disponível
- Flexibilidade — cada tipo resolve um problema específico
10. SQL e NoSQL Juntos (Polyglot Persistence)
Na prática, muitas aplicações modernas usam ambos — cada banco para o que faz melhor. Isto chama-se polyglot persistence.
Exemplo: Arquitectura de e-commerce
| Camada | Banco | Tipo | Razão |
|---|---|---|---|
| Pedidos e pagamentos | PostgreSQL | SQL | ACID, transacções, consistência forte |
| Catálogo de produtos | MongoDB | Documento | Schema flexível — cada produto tem atributos diferentes |
| Carrinho de compras | Redis | Chave-Valor | TTL automático, baixa latência (< 1ms) |
| Busca de produtos | Elasticsearch | Search | Full-text, facets, filtros, relevância |
| Sessões de utilizador | Redis | Chave-Valor | TTL, partilhado entre servidores |
| Recomendações | Neo4j | Gráfico | “Quem comprou X também comprou Y” |
| Analytics de vendas | ClickHouse | Colunar | Agregações em bilhões de registos |
Exemplo: Arquitectura de rede social
| Camada | Banco | Tipo | Razão |
|---|---|---|---|
| Perfil, mensagens | PostgreSQL | SQL | Dados estruturados, relações |
| Timeline / feed | Cassandra | Colunar | Escritas massivas, AP, multi-datacenter |
| Cache de feed | Redis | Chave-Valor | Baixa latência para feed |
| Amizades / relações | Neo4j | Gráfico | Relações complexas, recomendações |
| Notificações | Redis Pub/Sub | Chave-Valor | Tempo real |
| Busca de utilizadores | Elasticsearch | Search | Full-text, autocomplete |
11. Erros Comuns
- “NoSQL substitui SQL” — não substitui. Resolve problemas diferentes. Aplicações financeiras, ERP e sistemas transaccionais continuam a precisar de SQL.
- “MongoDB é mais rápido que PostgreSQL” — depende da query. PostgreSQL com índices correctos é frequentemente mais rápido para queries com filtros e JOINs. MongoDB é mais rápido para leitura por ID de documentos grandes.
- “NoSQL não tem schema, logo é mais flexível” — a flexibilidade cria dívida técnica. Sem schema, a validação passa para a aplicação e dados inválidos entram silenciosamente.
- “SQL não escala” — escala verticalmente até limites muito altos (PostgreSQL em servidores com 256GB RAM e 64 cores). Para a maioria das PME, isto é mais que suficiente.
- “Escolher pelo que a equipa conhece” — se a aplicação precisa de Cassandra e a equipa só sabe PostgreSQL, formar a equipa. Não forçar PostgreSQL num cenário que precisa de escrita distribuída massiva.
- “Usar NoSQL para tudo porque é moderno” — NoSQL não é “melhor”, é diferente. Cada tipo resolve um problema específico. Usar MongoDB para transacções financeiras é tão errado como usar Cassandra para dados relacionais com JOINs.
- “Ignorar consistência eventual” — em bancos AP (Cassandra, DynamoDB), ler imediatamente após escrever pode devolver dados desactualizados. Se a aplicação precisa de leitura após escrita consistente, usar consistência forte (ConsistentRead no DynamoDB) ou SQL.
- “Misturar sem saber porquê” — usar PostgreSQL + MongoDB + Redis + Elasticsearch sem uma razão clara para cada um cria complexidade operacional desnecessária. Cada banco adicional é uma peça mais para monitorizar, fazer backup e manter.
12. Checklist de Decisão
- Tipo de dados — estruturado com relações (SQL) ou semi-estruturado/flexível (NoSQL)?
- Transacções — preciso de ACID multi-operação (SQL) ou consistência eventual é aceitável (NoSQL)?
- Schema — é estável e bem definido (SQL) ou evolui frequentemente (NoSQL documento)?
- Relações — preciso de JOINs complexos (SQL) ou leio por ID/chave (NoSQL)?
- Escala — volume cabe num servidor (SQL) ou preciso distribuir por múltiplos nós (NoSQL)?
- Consistência — leitura sempre actualizada (SQL/CP) ou eventual é ok (NoSQL/AP)?
- Latência — posso tolerar 1-10ms (SQL) ou preciso de < 1ms (Redis)?
- Padrão de acesso — queries ad-hoc flexíveis (SQL) ou acesso por chave conhecida (NoSQL)?
- Multi-região — preciso de baixa latência global (NoSQL AP) ou single-region (SQL)?
- Equipa — conhece SQL (maioria dos devs) ou precisa formação em NoSQL?
- Budget — open-source self-hosted ou cloud gerido (DynamoDB, CosmosDB)?
- Ecossistema — precisa de ORM, ferramentas BI, reporting (SQL tem mais) ou API nativa chega (NoSQL)?
