MÓDULO 03 · 3 SEMANAS · BANCOS DE DADOS

Bancos de Dados

A escolha de storage é metade da arquitetura — e a maior parte das decisões caras de uma vida útil de sistema.

Duração ~3 semanas
Conceitos 8 fundamentais
Projeto Catálogo otimizado
Pré-requisito Módulos 00, 01 e 02
Performance Escalabilidade Confiabilidade

Oito ideias que mudam como você desenha schemas, escreve queries e decide entre storages. Quem entende de banco economiza ordens de magnitude em latência, custo e dor operacional.

01

Modelagem relacional & normalização

Codd, formas normais, e por que desnormalizar é decisão consciente — não preguiça. Modelagem do domínio em tabelas que envelhecem bem.

estudar →
02

Índices em profundidade — B-tree, hash, GiST, GIN

Como funcionam por dentro, quando ajudam, quando atrapalham. Covering indexes, índices parciais, e o custo invisível de cada índice em escrita.

estudar →
03

Transações & ACID — isolamento e MVCC

Read uncommitted, read committed, repeatable read, serializable. Anomalias (dirty/non-repeatable/phantom). MVCC em Postgres explicado.

estudar →
04

Plano de execução & otimização de queries

EXPLAIN ANALYZE sem mistério. Sequential scan vs index scan, joins (nested loop, hash, merge), estatísticas e quando o otimizador erra.

estudar →
05

Migrations & evolução de schema

Versionamento, rollback, expand-contract, zero-downtime. Como evoluir banco de produção sem janelas de manutenção.

estudar →
06

NoSQL: quando faz sentido

Document, key-value, column-family, graph. CAP aplicado, BASE vs ACID, e o caminho de volta para SQL quando o entusiasmo passa.

estudar →
07

Replicação, sharding & particionamento

Primary-replica, leituras em réplica, lag de replicação. Sharding por chave, partitioning lógico em Postgres, hot shards e o custo do rebalanceamento.

estudar →
08

ORMs e suas armadilhas

N+1, lazy loading, leaky abstractions. Quando o ORM acelera e quando atrapalha. EF Core, SQLAlchemy, sqlc/GORM lado a lado.

estudar →
princípio orientador

Banco não é detalhe de implementação — é a parte do sistema mais difícil de mudar depois. Schema mal-feito persiste por anos; índice errado custa em milissegundos a cada request; ORM mal-entendido faz o time culpar o "Postgres lento" quando o lento é o código. Tratar banco como caixa-preta é a maneira mais cara de aprender.

Decisões de banco têm vida útil de anos. Vale articular cada trade-off antes que a escolha vire dívida estrutural.

Postgres ou MongoDB para a maioria dos sistemas novos?

Postgres, em quase todos os casos. JSONB cobre o caso "preciso de campos flexíveis" sem abrir mão de transações fortes, joins, constraints e EXPLAIN. MongoDB venceria em workloads massivamente write-heavy de documentos sem relacionamento — um cenário muito mais raro do que o hype sugere. Quem começa em SQL e descobre que precisa de NoSQL aprende com base em evidência. Quem começa em NoSQL e descobre que precisa de joins paga o preço da migração.

Normalizar até a 3FN ou desnormalizar de início?

Modele em 3FN como default. Desnormalize só quando uma query específica, medida, mostrar gargalo claro — e quando a duplicação tiver estratégia explícita de manutenção (triggers, eventos, views materializadas). "Desnormalizar para performance" sem medição é desculpa para esquema bagunçado. A 3FN raramente é o gargalo real; índice ausente, sim.

Read committed ou repeatable read como default?

Postgres usa read committed; MySQL InnoDB usa repeatable read. As duas escolhas são razoáveis. Entender qual sua ferramenta usa, e quando subir para serializable em transação específica, importa mais do que mudar o default. Para lógica de negócio que depende de ler-modificar-escrever, prefira SELECT FOR UPDATE ou serializable explicitamente — e teste sob concorrência.

ORM em todo lugar ou SQL puro nas queries críticas?

Mistura. ORM acelera CRUD trivial e preserva tipagem entre código e schema. Para queries críticas — relatórios, agregações, joins grandes — escreva SQL e teste com EXPLAIN. ORM tentando gerar SQL otimizado para casos complexos costuma produzir queries piores que o SQL escrito à mão por alguém que entende do banco. sqlc e Dapper fazem essa divisão limpa; EF Core e SQLAlchemy permitem queries cruas quando preciso.

Quando começar a pensar em sharding?

Tarde. Quase sempre depois de réplicas de leitura, partitioning lógico no mesmo nó e tuning de queries. Sharding adiciona complexidade enorme: chaves de shard cruzadas, rebalanceamento, transações distribuídas. Postgres num servidor decente aguenta terabytes e dezenas de milhares de TPS. Antes de shardar, esgote verticalização, índices, cache e read replicas — costumam resolver.

Construir um catálogo real força você a sentir cada conceito do módulo — modelagem, índices, transações, migrations, planos de execução.

PROJETO PRÁTICO

Catálogo de produtos com queries otimizadas + histórico de migrations

Um catálogo (produtos, categorias, estoque, pedidos, audit log) com schema versionado, queries de listagem e busca otimizadas com EXPLAIN ANALYZE documentado, e comparação direta entre ORM e SQL puro nas operações críticas. Postgres em container, conjunto de seeds com 1M+ registros para performance virar mensurável.

REQUISITOS
  • Schema com 6-8 tabelas relacionadas em 3FN
  • Migrations versionadas com rollback testado (Flyway / EF Migrations / Alembic / golang-migrate)
  • Seed com 1M+ produtos para queries virarem perceptíveis
  • Pelo menos 3 índices documentados (escolha justificada por EXPLAIN)
  • Soft-delete + audit trail + optimistic locking
  • Query de listagem paginada com cursor (não OFFSET)
  • Comparativo SQL puro vs ORM em uma query complexa, com tempos medidos
  • Um exemplo de transação serializable para resolver corrida em estoque
  • Réplica de leitura configurada (mesmo que docker-compose) e leitura roteada
Performance Confiabilidade
STACK SUGERIDA POR LINGUAGEM
STACK
.NET 10 + EF Core 9 + Npgsql + Dapper (queries críticas) + EF Migrations + Testcontainers + xUnit
ESTRUTURA / NOTAS
  • Catalog.Domain/ (entidades + invariantes)
  • Catalog.Infra/ (DbContext, Migrations, Repositórios)
  • Catalog.Infra.Queries/ (Dapper para reports e listagens)
  • Catalog.Api/ (Minimal API)
  • Catalog.Tests.Integration/ (Testcontainers + Postgres)
  • EF Core para CRUD; Dapper onde EXPLAIN mostrar pior plano
  • Npgsql.EntityFrameworkCore.PostgreSQL como provider
STACK
Python 3.13 + SQLAlchemy 2.0 (Core + ORM) + Alembic + asyncpg (queries críticas) + FastAPI + Testcontainers
ESTRUTURA / NOTAS
  • catalog/domain/ (modelos imutáveis de domínio)
  • catalog/infra/db.py (engine, session)
  • catalog/infra/repositories.py (SQLAlchemy ORM)
  • catalog/infra/queries.py (Core/text para reports)
  • catalog/api/ (FastAPI)
  • migrations/ (Alembic, com rollback)
  • tests/integration/ (Testcontainers)
STACK
Go 1.23 + pgx + sqlc (codegen) + golang-migrate + chi/echo + Testcontainers-Go
ESTRUTURA / NOTAS
  • internal/catalog/domain/ (structs de domínio)
  • internal/catalog/store/ (gerado por sqlc — type-safe)
  • internal/catalog/queries.sql (escritas à mão, geradas com sqlc)
  • internal/api/ (chi router)
  • migrations/ (golang-migrate, com .up.sql e .down.sql)
  • tests/integration/ (Testcontainers-Go)
  • sqlc é a escolha sênior em Go: SQL puro com checagem em build
entregável

Repositório com README documentando: cada índice criado e o EXPLAIN antes/depois, cada migration com seu plano de rollback, e um ADR explicando a escolha entre ORM e SQL puro em duas queries específicas — com tempos de execução medidos sob carga de 1M+ registros. O ganho de performance documentado é a evidência de entendimento.

Banco aparece em quase toda entrevista de sênior. As perguntas abaixo cobrem a faixa que diferencia quem usa Postgres de quem entende Postgres.

Q.01

Explique os níveis de isolamento. Em qual você corre risco de ler dados que serão revertidos? Em qual você ainda corre risco de phantom read?

Q.02

Você tem uma tabela com 200M de linhas e uma query lenta. Como investigar? O que EXPLAIN ANALYZE mostra que EXPLAIN não mostra?

Q.03

Quando faz sentido criar um índice composto? Como decidir a ordem das colunas? Quando um índice atrapalha em vez de ajudar?

Q.04

Como você adiciona uma coluna NOT NULL numa tabela de 50M linhas em produção, sem janela de manutenção?

Q.05

N+1 query — explique o problema, como detectar (ferramentas e métricas) e três formas de resolver com trade-offs distintos.