Skip to main content
backend30 de novembro de 202513 min de leitura

Escolhendo o Banco de Dados Certo: Relacional vs NoSQL para Projetos Reais

Um framework prático de decisão para escolher entre PostgreSQL, MongoDB, Firebase, Redis e outros bancos de dados com base nos seus requisitos reais.

databasepostgresqlmongodb
Escolhendo o Banco de Dados Certo: Relacional vs NoSQL para Projetos Reais

"Depende" é a resposta honesta para toda pergunta sobre banco de dados, mas também é inútil. Quando você está começando um projeto e precisa escolher um banco de dados, precisa de algo mais concreto do que uma lista de trade-offs. Você precisa de um framework de decisão que considere seus requisitos reais — formato dos dados, padrões de consulta, experiência da equipe, expectativas de escala e complexidade operacional.

Já usei PostgreSQL, MongoDB, Firebase/Firestore, Redis e SQLite em diferentes projetos em produção. Cada escolha foi certa para seu contexto, e algumas foram erradas e precisaram ser migradas. Os padrões por trás dessas decisões são mais úteis do que qualquer comparação de benchmark.

O Framework de Decisão

Antes de analisar bancos de dados individuais, responda estas cinco perguntas sobre seu projeto:

1. Qual é o formato dos seus dados?

Isso não é sobre "relacional vs documento". É sobre como suas entidades de dados se relacionam entre si.

Altamente relacional: Usuários têm pedidos, pedidos têm itens, itens pertencem a categorias, categorias têm hierarquias. Se você desenhar seu modelo de dados e ele parecer um grafo com muitas conexões, você precisa de fortes capacidades relacionais.

Orientado a documentos: Cada entidade é relativamente autocontida. Um post de blog contém seu título, corpo, tags e informações do autor. Você raramente precisa fazer joins entre tipos de entidade.

Chave-valor: Você precisa armazenar e recuperar por chave. Dados de sessão, configuração, feature flags.

Séries temporais: Eventos, métricas, logs. Escrita intensiva, somente inserção, consultado por intervalo de tempo.

2. Quais são seus padrões de consulta?

Consultas conhecidas: Você sabe exatamente quais queries a aplicação vai executar. E-commerce: "buscar pedidos do usuário", "encontrar produtos por categoria", "calcular receita total deste mês". Consultas conhecidas favorecem bancos de dados relacionais onde você pode otimizar com índices e planos de execução.

Consultas ad-hoc: Usuários podem buscar, filtrar e agregar de maneiras imprevisíveis. Dashboards de analytics, funcionalidades de busca, ferramentas de relatório. Essas favorecem motores de consulta flexíveis.

Buscas simples: A maioria das leituras é "buscar documento por ID". Bancos de dados de documentos e armazenamentos chave-valor se destacam aqui.

3. Qual é o seu requisito de consistência?

Consistência forte: Bancário, estoque, qualquer coisa onde ler dados desatualizados causa problemas reais. Bancos de dados relacionais com transações ACID são a escolha segura.

Consistência eventual: Feeds sociais, analytics, cache. Você pode tolerar ler dados ligeiramente desatualizados em troca de performance e disponibilidade.

4. Qual é sua trajetória de escala?

Escalabilidade vertical é suficiente: A maioria das aplicações. Se seu banco de dados cabe em uma única máquina com espaço para crescer, qualquer banco de dados funciona. PostgreSQL em um servidor moderno lida com milhões de linhas sem dificuldade.

Escalabilidade horizontal é necessária: Você precisa distribuir dados entre múltiplas máquinas. Isso é mais raro do que a maioria dos desenvolvedores pensa, mas quando você precisa, sua escolha de banco de dados fica limitada.

5. O que sua equipe conhece?

Este fator é subestimado. Uma equipe de especialistas em PostgreSQL será mais produtiva com PostgreSQL, mesmo que MongoDB seja teoricamente mais adequado para o modelo de dados. O custo de aprender um novo banco de dados — debugar erros desconhecidos, aprender melhores práticas operacionais, entender características de performance — é real e significativo.

PostgreSQL: A Escolha Padrão

Se você não tem certeza, escolha PostgreSQL. Isso não é uma opinião controversa entre engenheiros de backend — é o consenso. PostgreSQL lida com dados relacionais, documentos JSON, busca textual, consultas geoespaciais e dados de séries temporais. Não é o melhor em nenhum desses isoladamente, mas é bom o suficiente em todos eles para servir como banco de dados único para a maioria das aplicações.

Pontos Fortes

Transações ACID. Quando você precisa atualizar múltiplas tabelas atomicamente — deduzindo estoque e criando um pedido, transferindo dinheiro entre contas — PostgreSQL garante a correção.

Capacidades ricas de consulta. Window functions, CTEs (Common Table Expressions), consultas recursivas, lateral joins. SQL não é apenas SELECT * FROM — é uma linguagem de consulta poderosa que pode expressar analytics complexas sem mover dados para a camada de aplicação.

-- Find each user's most recent order with running total
WITH ranked_orders AS (
  SELECT
    user_id,
    order_id,
    total,
    created_at,
    ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) as rn,
    SUM(total) OVER (PARTITION BY user_id ORDER BY created_at) as running_total
  FROM orders
)
SELECT * FROM ranked_orders WHERE rn = 1;

Colunas JSONB. Quando parte dos seus dados é genuinamente sem schema — preferências de usuário, respostas de formulários dinâmicos, payloads de webhooks de terceiros — você pode armazenar como JSONB e consultar com suporte completo a indexação.

-- Store and query semi-structured data
CREATE TABLE products (
  id SERIAL PRIMARY KEY,
  name TEXT NOT NULL,
  attributes JSONB DEFAULT '{}'
);

-- Index a specific JSON path
CREATE INDEX idx_products_color ON products USING GIN ((attributes->'color'));

-- Query JSON data
SELECT name FROM products
WHERE attributes->>'color' = 'blue'
AND (attributes->>'weight')::numeric < 10;

Ecossistema de extensões. PostGIS para geoespacial, pg_trgm para busca textual fuzzy, TimescaleDB para séries temporais, pgvector para embeddings de IA. O modelo de extensões significa que PostgreSQL pode se adaptar a workloads especializados sem substituir seu banco de dados principal.

Quando PostgreSQL Não É a Escolha Certa

  • Throughput massivo de escrita com escalabilidade horizontal. PostgreSQL escala verticalmente bem (máquina maior), mas sharding horizontal é complexo. Se você precisa escrever milhões de eventos por segundo em dezenas de máquinas, considere soluções específicas para isso.
  • Prototipagem rápida onde mudanças de schema acontecem diariamente. Nos estágios mais iniciais de uma startup, quando o modelo de dados muda fundamentalmente toda semana, a sobrecarga de migrações pode te atrasar comparado a opções sem schema.
  • Quando sua equipe não tem nenhuma experiência com SQL e o cronograma do projeto não permite aprendizado. Isso é raro, mas acontece.

MongoDB: Quando Documentos Fazem Sentido

MongoDB recebe mais críticas do que merece. O marketing inicial ("sem schema! escala web!") criou expectativas irrealistas, e muitos desenvolvedores o usaram para casos de uso onde PostgreSQL teria sido melhor. Mas existem cenários genuínos onde MongoDB é a escolha certa.

Quando MongoDB Vence

Sistemas de gerenciamento de conteúdo. Cada peça de conteúdo tem uma estrutura diferente — artigos têm campos diferentes de vídeos, que têm campos diferentes de podcasts. No MongoDB, todos são documentos na mesma collection com formatos diferentes. No PostgreSQL, você ou cria uma tabela ampla com muitas colunas anuláveis, usa colunas JSON (e nesse ponto está usando o paradigma do MongoDB dentro do PostgreSQL), ou cria uma tabela por tipo com joins complexos.

Event sourcing e logging. Alto throughput de escrita com documentos que são majoritariamente escritos e lidos, raramente atualizados e nunca sofrem join.

Documentos embutidos reduzem joins. Se um pedido sempre precisa dos seus itens, e itens nunca são acessados sem seu pedido, embutir itens dentro do documento do pedido significa que sua consulta mais comum é uma busca de documento único em vez de um join entre duas tabelas.

// MongoDB document with embedded sub-documents
{
  _id: ObjectId("..."),
  customer: {
    name: "John Doe",
    email: "john@example.com"
  },
  items: [
    { product: "Widget", quantity: 2, price: 9.99 },
    { product: "Gadget", quantity: 1, price: 24.99 }
  ],
  total: 44.97,
  status: "shipped",
  createdAt: ISODate("2026-03-01T10:00:00Z")
}

Escalabilidade horizontal é uma funcionalidade de primeira classe. O sharding do MongoDB é nativo e bem documentado. Se você genuinamente precisa distribuir dados entre muitos nós (centenas de milhões de documentos com alto throughput), MongoDB lida com isso de forma mais elegante que PostgreSQL.

Quando MongoDB Está Errado

  • Dados altamente relacionais. Se você está escrevendo agregações $lookup (a versão de joins do MongoDB) em toda consulta, você escolheu o banco de dados errado.
  • Quando você precisa de transações entre collections frequentemente. MongoDB suporta transações multi-documento, mas elas adicionam latência e complexidade. Se suas operações principais requerem atomicidade entre collections, o modelo de transações do PostgreSQL é mais natural.
  • Quando você realmente precisa de um schema. "Sem schema" soa libertador até você perceber que cada pedaço de código que lê do banco de dados é implicitamente um schema. Sem um schema imposto pelo banco de dados, você move a validação para a camada de aplicação, onde é mais fácil errar e mais difícil impor consistentemente.

Firebase e Firestore: Desenvolvimento Rápido

Firebase Realtime Database e Firestore servem um nicho específico: aplicações onde a velocidade de desenvolvimento importa mais que a pureza do modelo de dados, e onde o backend é primariamente uma camada de persistência e sincronização de dados em vez de um motor complexo de lógica de negócios.

Quando Firebase Brilha

Apps mobile-first com sincronização em tempo real. Os SDKs do Firebase lidam com cache offline, listeners em tempo real e resolução de conflitos nativamente. Construir isso do zero com PostgreSQL requer uma camada de WebSocket, uma estratégia de cache e código customizado significativo.

Equipes pequenas sem engenheiros de backend. Firebase elimina a necessidade de gerenciar um servidor de banco de dados, construir uma camada de API, implementar autenticação e lidar com armazenamento de arquivos. Para uma equipe de duas pessoas construindo um MVP, essa redução na sobrecarga operacional pode ser a diferença entre lançar e não lançar.

Prototipagem e validação. Quando você precisa testar uma ideia com usuários reais em duas semanas, Firebase permite que você foque inteiramente na aplicação cliente. Se a ideia for validada, você pode migrar para um backend mais tradicional depois.

Limitações do Firebase

Restrições de consulta no Firestore. Você não pode consultar campos que não estão indexados. Não pode fazer filtros de desigualdade em múltiplos campos. Não pode fazer busca textual. Essas limitações forçam você a desnormalizar agressivamente e às vezes duplicar dados entre collections.

// Firestore: You CAN'T do this
db.collection('products')
  .where('price', '>', 10)
  .where('rating', '>', 4)
  .orderBy('name')  // Error: needs composite index on price + rating + name

// Firestore: You CAN do this (with a composite index)
db.collection('products')
  .where('price', '>', 10)
  .where('rating', '>', 4)
  .orderBy('price')  // Must order by a field used in inequality

Vendor lock-in. Seu modelo de dados, regras de segurança e padrões de consulta são todos específicos do Firebase. Migrar do Firebase é uma reescrita, não uma migração.

Imprevisibilidade de custos. Firebase cobra por leitura/escrita de documento. Uma consulta mal otimizada ou um listener em tempo real em uma collection grande pode gerar contas surpreendentes. Já vi projetos onde um único listener mal configurado custou mais do que um servidor PostgreSQL dedicado custaria por um ano.

Lógica server-side limitada. Cloud Functions podem lidar com algum processamento server-side, mas lógica de negócios complexa — transações de múltiplas etapas, agregação de dados, processamento em background — requer ou workarounds criativos ou um backend separado de qualquer forma.

Decisão: Firebase vs Backend Tradicional

Fator Firebase PostgreSQL + API
Tempo até o MVP Dias Semanas
Sobrecarga operacional Quase zero Moderada
Flexibilidade de consulta Limitada SQL completo
Custo em escala Imprevisível Previsível
Vendor lock-in Alto Baixo
Suporte offline Nativo Precisa construir
Lógica de negócios complexa Difícil Natural
Equipe necessária Apenas frontend Frontend + Backend

Redis: Cache, Filas e Mais

Redis não é um banco de dados principal para a maioria das aplicações (embora Redis com módulos de persistência possa servir esse papel). É um armazenamento de estruturas de dados de alta performance que se destaca em problemas específicos.

Cache

O caso de uso mais comum do Redis. Faça cache de consultas de banco de dados caras, respostas de API ou resultados computados.

import redis
import json

r = redis.Redis(host='localhost', port=6379, db=0)

def get_user_profile(user_id: str):
    # Check cache first
    cached = r.get(f"user:{user_id}")
    if cached:
        return json.loads(cached)

    # Cache miss — query database
    profile = db.query("SELECT * FROM users WHERE id = %s", user_id)

    # Cache for 5 minutes
    r.setex(f"user:{user_id}", 300, json.dumps(profile))
    return profile

Armazenamento de Sessão

O modelo chave-valor do Redis com suporte a TTL (time-to-live) é um encaixe natural para dados de sessão. É mais rápido que sessões em banco de dados e mais simples que soluções baseadas em JWT para aplicações stateful.

Rate Limiting

def is_rate_limited(user_id: str, limit: int = 100, window: int = 60) -> bool:
    key = f"rate:{user_id}"
    current = r.incr(key)
    if current == 1:
        r.expire(key, window)
    return current > limit

Filas de Trabalho

Listas e streams do Redis são excelentes filas de trabalho. Bibliotecas como Bull (Node.js), Celery (Python) e Sidekiq (Ruby) usam Redis como seu message broker.

Quando Não Usar Redis

  • Como seu único banco de dados. Redis é in-memory por padrão. Mesmo com persistência (snapshots RDB ou logs AOF), não foi projetado para dados que você não pode perder.
  • Para consultas complexas. As estruturas de dados do Redis (strings, listas, sets, sorted sets, hashes) são poderosas, mas não consultáveis como um banco de dados. Você acessa dados por chave, não por condições arbitrárias.
  • Quando você não tem um problema de cache. Adicionar Redis a uma stack que não precisa de cache adiciona complexidade operacional sem benefício. Uma consulta PostgreSQL que leva 5ms não precisa de cache.

Usando Múltiplos Bancos de Dados

A maioria das aplicações em produção de complexidade moderada usa mais de um banco de dados. A chave é usar cada um para o que faz de melhor, não tentar forçar um banco de dados a lidar com tudo.

Um padrão comum para uma aplicação web:

  • PostgreSQL para dados centrais do negócio (usuários, pedidos, produtos).
  • Redis para cache, sessões e rate limiting.
  • S3 (ou equivalente) para armazenamento de arquivos (imagens, documentos, backups).

Para uma aplicação em tempo real:

  • PostgreSQL para dados persistentes e consultas complexas.
  • Redis para pub/sub e cache.
  • Firebase/Supabase para sincronização em tempo real com clientes mobile.

O Padrão de Integração

Ao usar múltiplos bancos de dados, estabeleça propriedade clara. Cada dado tem uma fonte autoritativa, e outros sistemas são caches ou visualizações desse dado.

PostgreSQL (source of truth)
    ├── Redis (read cache, expires after TTL)
    ├── Elasticsearch (search index, synced via change data capture)
    └── Firebase (mobile sync, updated via webhooks)

Nunca tenha dois bancos de dados que ambos se considerem donos do mesmo dado. Esse caminho leva a pesadelos de consistência que são quase impossíveis de debugar.

Considerações de Migração

Se você perceber que escolheu o banco de dados errado, migração é possível, mas cara. Aqui estão as considerações práticas:

MongoDB para PostgreSQL é a migração mais comum que já vi. A razão usual é que a aplicação cresceu além de consultas de documentos e passou a precisar de joins complexos, transações ou agregações. A migração envolve projetar um schema relacional, escrever scripts de transformação e atualizar cada consulta de banco de dados na aplicação. Reserve duas a quatro semanas para uma aplicação de complexidade moderada.

PostgreSQL para MongoDB é mais rara, mas acontece quando o modelo de dados de uma aplicação se torna predominantemente orientado a documentos. A migração é mecanicamente mais simples (achatar tabelas em documentos), mas requer repensar cada consulta e perder garantias transacionais.

Firebase para PostgreSQL é a migração mais difícil porque não é apenas uma troca de banco de dados — é uma mudança de arquitetura. Você precisa construir uma camada de API, implementar autenticação, substituir listeners em tempo real por WebSockets ou polling, e lidar com sincronização offline. Isso é mais próximo de uma reescrita do que de uma migração.

A melhor migração é aquela que você evita. Gaste um dia extra pensando no seu modelo de dados antecipadamente. Converse com alguém que construiu uma aplicação similar. O custo de escolher o banco de dados certo inicialmente é sempre menor que o custo de migrar depois.

Análise de Custos

Custos de banco de dados em escala podem surpreender, especialmente com serviços gerenciados.

Serviço Plano Gratuito Produção Pequena Produção Média
Supabase (PostgreSQL) 500MB, 2 projetos ~$25/mês (8GB, 2 cores) ~$100/mês (32GB, 4 cores)
Neon (PostgreSQL) 0.5GB armazenamento ~$19/mês ~$69/mês
MongoDB Atlas 512MB compartilhado ~$57/mês (M10 dedicado) ~$200/mês (M30)
Firebase Firestore 1GB armazenamento, 50k leituras/dia ~$25-100/mês (varia muito) $100-1000/mês (depende das consultas)
Redis Cloud 30MB ~$7/mês (250MB) ~$60/mês (1GB)
PlanetScale (MySQL) 5GB, 1B leituras de linha/mês ~$39/mês ~$99/mês

A imprevisibilidade de custos do Firebase merece destaque. Já vi projetos onde os custos ficaram abaixo de $30/mês por meses, e então dispararam para $300 após o lançamento de uma funcionalidade que aumentou as leituras de documentos. Com PostgreSQL ou MongoDB, os custos são proporcionais ao tamanho da máquina, o que é previsível.

Meu Processo Real de Decisão

Quando começo um novo projeto, a decisão geralmente segue assim:

  1. PostgreSQL como padrão, a menos que haja uma razão específica para não usar.
  2. Adicionar Redis se a aplicação tem necessidades de cache, rate limiting ou filas de trabalho.
  3. Considerar Firebase/Supabase se a aplicação é mobile-first com requisitos de tempo real e a equipe é pequena.
  4. Considerar MongoDB se o modelo de dados é genuinamente orientado a documentos com requisitos relacionais mínimos.
  5. Adicionar bancos de dados especializados (Elasticsearch, TimescaleDB, etc.) apenas quando um workload específico exige.

Este framework tem me servido bem em uma variedade de projetos, de plataformas de gestão de restaurantes a aplicações mobile de saúde. O insight principal é que o banco de dados é infraestrutura — ele deve servir às necessidades da sua aplicação, não direcionar sua arquitetura. Escolha a opção comprovada que funciona e gaste seu esforço de engenharia nas partes da aplicação que te diferenciam.

DU

Danil Ulmashev

Full Stack Developer

Interesse em trabalhar juntos?