continuous learning company
Voltar para publicações
Necy Vieira
Necy Vieira Conheça o autor

Modelagem SQL vs NoSQL: Como Mudar a Forma de Pensar

Tabelas normalizadas ou documentos com dados aninhados? Entenda a inversão de pensamento entre os dois mundos, com exemplos práticos de voos e de uma loja online.

18/09/2026 Bancos de Dados
Infográfico de modelagem SQL vs NoSQL: tabelas normalizadas com chaves estrangeiras versus documento único com dados aninhados, a inversão de pensamento query-first e os 3 pilares: denormalização, embed vs reference e query-first design

Quem aprendeu bancos de dados com SQL costuma cometer o mesmo erro ao chegar no NoSQL: desenhar as mesmas tabelas, só que chamando de "coleções". O banco muda, mas a cabeça continua a mesma — e o resultado é um modelo que funciona mal nos dois mundos.

A boa notícia é que existe uma lógica simples por trás da diferença. Neste post, vou mostrar essa lógica com exemplos práticos, do jeito mais direto possível. Os exemplos de NoSQL usam o formato de documentos JSON, como no MongoDB, o banco de documentos mais conhecido.

Se você quer uma visão geral das diferenças entre os dois tipos de banco, comece por SQL vs NoSQL: Entenda as Diferenças na Prática. Aqui o foco é outro: como modelar.

1. O Mesmo Problema, Dois Modelos

Imagine um sistema de passagens aéreas. Precisamos guardar aviões, aeroportos e voos. Um voo usa um avião e liga um aeroporto de origem a um de destino.

No SQL: dados separados e conectados por chaves

A abordagem SQL é normalizar: cada informação vive em um único lugar (sua própria tabela) e as tabelas se conectam por chaves estrangeiras (FK).

CREATE TABLE aviao (
  id_aviao   VARCHAR(10) PRIMARY KEY,
  modelo     VARCHAR(50),
  fabricante VARCHAR(50),
  capacidade INT
);

CREATE TABLE aeroporto (
  id_aeroporto CHAR(3) PRIMARY KEY,
  nome         VARCHAR(100),
  cidade       VARCHAR(50),
  pais         VARCHAR(50)
);

CREATE TABLE voo (
  id_voo               VARCHAR(10) PRIMARY KEY,
  id_aviao             VARCHAR(10) REFERENCES aviao (id_aviao),
  id_aeroporto_origem  CHAR(3)     REFERENCES aeroporto (id_aeroporto),
  id_aeroporto_destino CHAR(3)     REFERENCES aeroporto (id_aeroporto),
  data_hora            TIMESTAMP,
  preco                DECIMAL(10,2)
);

Para montar a tela de detalhes de um voo, precisamos juntar tudo com JOIN:

SELECT v.id_voo, v.data_hora, v.preco,
       a.modelo,
       o.cidade AS origem,
       d.cidade AS destino
FROM voo v
JOIN aviao a      ON a.id_aviao = v.id_aviao
JOIN aeroporto o  ON o.id_aeroporto = v.id_aeroporto_origem
JOIN aeroporto d  ON d.id_aeroporto = v.id_aeroporto_destino
WHERE v.id_voo = 'VO123';

Resumo do SQL: mais tabelas, mais joins, mais regras. Em troca, você ganha consistência e integridade: se o nome de um aeroporto mudar, basta atualizar uma única linha.

No NoSQL: um documento com tudo que a tela precisa

Em um banco de documentos, a abordagem é guardar os dados relacionados juntos, dentro de um único documento:

{
  "_id": "VO123",
  "data_hora": "2026-05-20T08:30:00Z",
  "preco": 850.00,
  "aviao": {
    "id": "AV001",
    "modelo": "Boeing 737",
    "fabricante": "Boeing",
    "capacidade": 180
  },
  "aeroporto_origem": {
    "id": "GRU",
    "nome": "São Paulo/Guarulhos",
    "cidade": "São Paulo",
    "pais": "Brasil"
  },
  "aeroporto_destino": {
    "id": "JFK",
    "nome": "John F. Kennedy Intl",
    "cidade": "Nova York",
    "pais": "EUA"
  }
}

E a consulta fica assim, sem nenhum join:

db.voos.find({ _id: "VO123" })

Resumo do NoSQL: menos joins, leitura rápida e direta, com os dados relacionados já prontos para uso. O preço é a repetição: o aeroporto GRU aparece em todos os voos que saem de lá.

2. A Inversão de Pensamento

Aqui está a virada de chave mais importante do post:

  • Pensamento SQL: "O que eu tenho?" Começo pelas entidades (produtos, categorias, avaliações) e depois descubro como consultá-las.
  • Pensamento query-first (NoSQL): "O que eu preciso mostrar?" Começo pelas telas e consultas da aplicação e desenho o documento a partir delas.

Exemplo: a página de produto de uma loja online

Nossa página de produto precisa mostrar: nome, preço, categoria e as 3 últimas avaliações.

Pensando como SQL, eu diria: "tenho Produtos, Categorias e Avaliações, então vou criar 3 coleções separadas com referências entre elas". Para montar a página, o banco precisaria buscar nas três:

db.produtos.aggregate([
  { $match: { _id: "P1001" } },
  { $lookup: {
      from: "categorias",
      localField: "categoria_id",
      foreignField: "_id",
      as: "categoria"
  } },
  { $lookup: {
      from: "avaliacoes",
      localField: "_id",
      foreignField: "produto_id",
      as: "avaliacoes"
  } }
])

Funciona, mas é o "join do SQL" disfarçado, e ainda falta ordenar e limitar as avaliações às 3 mais recentes.

Pensando query-first, eu diria: "minha página mostra tudo isso junto, então vou criar um documento que já contenha tudo isso pronto para exibir":

{
  "_id": "P1001",
  "nome": "Tênis Runner Pro",
  "preco": 129.90,
  "categoria": { "id": "C10", "nome": "Esportes" },
  "avaliacoes_recentes": [
    { "usuario": "Ana",   "nota": 5, "comentario": "Excelente produto!" },
    { "usuario": "Bruno", "nota": 4, "comentario": "Muito confortável" },
    { "usuario": "Carla", "nota": 5, "comentario": "Vale o preço" }
  ]
}
db.produtos.find({ _id: "P1001" })

Uma consulta, um documento, a tela inteira. É por isso que, no NoSQL, cada tela pode sugerir um modelo diferente. O objetivo é que a maioria das consultas seja atendida com um único find(), sem $lookup nem agregações complexas.

3. Os 3 Pilares na Prática

Para modelar bem em NoSQL, três ideias se repetem o tempo todo.

Pilar 1: Denormalização (foco: leitura rápida)

Denormalizar é repetir dados de forma estratégica para que a leitura seja rápida. Foi o que fizemos ao copiar o nome da categoria para dentro do produto.

O custo aparece quando o dado muda. Se a categoria "Esportes" for renomeada, será preciso atualizar todos os produtos que a carregam:

db.produtos.updateMany(
  { "categoria.id": "C10" },
  { $set: { "categoria.nome": "Esportes e Lazer" } }
)

Por isso a regra prática é: repita dados que mudam pouco (nome de categoria, cidade de um aeroporto) e aceite o trade-off de atualizá-los em mais de um lugar. Dados que mudam o tempo todo e são compartilhados por muitos documentos pedem mais cuidado.

Pilar 2: Embed vs Reference (foco: relações inteligentes)

Sempre que dois dados se relacionam, você escolhe entre duas opções:

  • Embed (embutir): colocar o dado relacionado dentro do documento.
  • Reference (referenciar): guardar só o identificador e manter o dado em outra coleção.

Um guia rápido para decidir:

  • Embuta quando os dados são lidos juntos e a relação é 1:1 ou 1:poucos. Exemplos: o endereço de entrega de um pedido, os 3 telefones de um cliente, as 3 últimas avaliações de um produto.
  • Referencie quando os dados são independentes ou crescem sem limite. Exemplos: todas as avaliações de um produto muito popular, ou todos os pedidos de um cliente ao longo dos anos.

O segundo caso é importante: um documento não pode crescer para sempre. No MongoDB, por exemplo, cada documento tem limite de 16 MB, e listas que só aumentam também deixam as leituras e as atualizações mais pesadas.

Quando nenhuma das duas opções serve sozinha, use um padrão híbrido. No nosso exemplo, o produto embute apenas as 3 avaliações mais recentes (para a página abrir rápido) e todas as avaliações continuam guardadas em uma coleção própria, referenciando o produto:

// Coleção "avaliacoes": histórico completo
{ "_id": "A9001", "produto_id": "P1001", "usuario": "Ana", "nota": 5, "comentario": "Excelente produto!" }

Assim você tem o melhor dos dois: leitura rápida na tela principal e histórico completo sem estourar o documento do produto.

Pilar 3: Query-First Design (foco: consultas eficientes)

É a ideia que amarra as outras duas: comece pelas telas e consultas, não pelas entidades. Cada documento deve ser projetado para atender a uma consulta específica com o mínimo de operações.

Na prática, antes de modelar, faça uma lista de perguntas:

  • Quais telas ou relatórios a aplicação terá?
  • Que dados aparecem juntos em cada tela?
  • Com que frequência cada consulta roda? E cada atualização?
  • Quais dados mudam com frequência e quais quase nunca mudam?

As respostas indicam o que embutir, o que referenciar e o que vale repetir.

Erros Comuns ao Modelar em NoSQL

  • Copiar o modelo relacional: criar uma coleção para cada tabela e depender de vários $lookup desperdiça a principal vantagem do modelo de documentos.
  • Embutir tudo, sem limite: listas que crescem para sempre (todos os pedidos dentro do cliente, por exemplo) acabam causando problemas.
  • Repetir dados que mudam toda hora: manter cópias sincronizadas vira um pesadelo.
  • Modelar sem conhecer as consultas: sem saber o que a aplicação precisa ler, é impossível escolher o modelo certo.

Quando o SQL Ainda É a Melhor Escolha?

Nada disso significa que o NoSQL seja "melhor". Se o seu sistema tem muitos relacionamentos, exige consistência forte entre várias entidades (como transações financeiras) e faz consultas variadas e imprevisíveis, o modelo relacional continua sendo uma ótima escolha. A modelagem NoSQL brilha quando você conhece bem os padrões de acesso e quer leitura rápida e escala.

Resumo Rápido

  • SQL: começa pelas entidades, normaliza os dados e usa joins na leitura.
  • NoSQL: começa pelas consultas, agrupa os dados que são lidos juntos e evita joins na leitura.
  • Denormalização: repita dados com estratégia, priorizando velocidade de leitura.
  • Embed vs Reference: embuta o que é lido junto e cresce pouco; referencie o que é independente ou cresce sem limite.
  • Query-first: cada documento nasce para responder a uma consulta específica.

Dica Final

Não existe modelo perfeito — existe modelo adequado ao seu caso de uso. Meça, itere e evolua o schema conforme a aplicação cresce.

Uma das grandes vantagens dos bancos de documentos é justamente a flexibilidade: você pode começar simples, observar como a aplicação realmente lê e grava os dados, e ajustar o modelo com o tempo.

E no seu projeto, você costuma partir das entidades ou das telas ao modelar os dados? Conte nos comentários como você decide entre embutir e referenciar!

Teste seu conhecimento

Responda às perguntas abaixo para revisar os principais pontos deste artigo.

1. Qual é a principal mudança de raciocínio do design query-first em NoSQL?

2. Em qual situação faz mais sentido referenciar (reference) em vez de embutir (embed) os dados?

3. O que é denormalização e qual é o seu principal custo?

4. No exemplo do voo, qual é a vantagem de guardar avião, origem e destino dentro de um único documento?

5. Segundo a dica final do artigo, como escolher o modelo de dados ideal?

Livros recomendados