Boas Práticas de Modelagem de Dados
Modele o domínio, não a tela atual da UI. Use esta lista durante revisões de schema, PRs de migração e atualizações de ADRs.
Como Usar Esta Lista
- Percorra de cima para baixo para tabelas novas (greenfield); use seções únicas para revisões direcionadas.
- Registre violações como tickets de migração com um responsável e prazo.
- Revise trimestralmente ou após qualquer incidente de corrupção de dados.
- Combine com
EXPLAINe consultas de integridade - erros de modelagem aparecem como órfãos e joins em leque (fan-out).
A - Fidelidade ao Domínio
- Nomeie tabelas com substantivos do domínio, não com rótulos de tela.
checkout_summary_rowse tornaorders+line_itemsquando a UI muda. - Codifique invariantes no banco de dados. Use constraints
NOT NULL,CHECK,UNIQUEe FKs - não apenas validação da aplicação. - Documente a propriedade da tabela em
COMMENT ON. Cada tabela de produção tem um único serviço escritor ou nome de equipe. - Prefira
timestamptzpara instantes. Armazene UTC; converta na exibição. Evitetimestamp without time zonepara eventos do usuário. - Use chaves de identidade
bigintsubstitutas para OLTP. Chaves naturais pertencem a constraintsUNIQUEquando garantidas pelo negócio.
B - Relacionamentos e Cardinalidade
- Resolva muitos-para-muitos com tabelas de junção. Nunca duplique colunas de tags (
tag1,tag2) em uma tabela de fatos. - Indexe cada coluna de chave estrangeira. FKs não indexadas causam joins lentos e cascades custosos ao excluir.
- Torne a opcionalidade explícita. Pai obrigatório: FK
NOT NULL; opcional: FK anulável maisLEFT JOINnas consultas. - Escolha
ON DELETEdeliberadamente.CASCADE,RESTRICTeSET NULLdevem corresponder às regras de negócio, não aos padrões. - Evite FKs entre contextos, a menos que as equipes façam deploy juntas. Prefira referências UUID lógicas entre contextos delimitados (bounded contexts).
C - Design Físico no PostgreSQL
- Mapeie contextos delimitados para schemas. Evite que
publicse torne uma gaveta de bagunça compartilhada. - Conceda o mínimo privilégio por role de aplicativo. Serviços não devem
UPDATEtabelas que não possuem. - Planeje a evolução do schema com expandir-contrair. Adicione colunas e views de compatibilidade antes de remover formas antigas.
- Snapshot de preços e rótulos em linhas transacionais.
order_items.unit_pricenão deve mudar quando o preço do catálogo muda. - Valide convenções de nomenclatura em CI.
snake_caseconsistente, tabelas plurais e sufixos_idaceleram revisões.
D - Operações e Longevidade
- Registre ADRs para topologia de banco de dados. Decisões de DB compartilhado único vs. DB por serviço precisam de uma data de revisão.
- Teste migrações em uma cópia das estatísticas de produção. Estimativas de cardinalidade afetam escolhas de índice e partição.
- Meça antes de desnormalizar. Prove a dor de leitura com
pg_stat_statements; documente invariantes de atualização se desnormalizar. - Execute consultas de detecção de órfãos após preenchimentos (backfills).
LEFT JOIN ... WHERE parent IS NULLdeve retornar zero linhas. - Deprecie views de compatibilidade em um calendário. Views sem datas de término se tornam lixo permanente.
FAQs
Por que modelar o domínio em vez da UI?
Telas mudam semanalmente; regras de domínio (um pedido tem itens de linha, um usuário tem um email) duram anos. Tabelas moldadas pela UI exigem migrações dolorosas quando a navegação muda.
Qual é a barra mínima de integridade para uma nova tabela?
Chave primária, created_at timestamptz, comentário de propriedade e constraints para cada regra de negócio que você consegue nomear em uma frase.
Quando devo desnormalizar?
Depois que o design normalizado estiver ativo e pg_stat_statements provar que o custo do join bloqueia SLOs. Documente o que deve permanecer sincronizado e como você detecta desvios.
Como impor a propriedade com múltiplos serviços?
Schemas separados, roles de banco de dados separados, checklist de revisão de código e, opcionalmente, REVOKE INSERT/UPDATE entre schemas das roles de aplicativo.
Toda coluna deve ter um comentário?
Comente tabelas e colunas não óbvias (enums de status, flags de soft-delete, suposições de moeda). Pule o ruído de nível id.
Qual é o principal erro de modelagem em SaaS?
Esquecer tenant_id em tabelas filhas ou índices que começam com tenant_id - causa vazamentos entre tenants e consultas lentas.
Como revisar um PR que adiciona uma coluna JSONB?
Pergunte: quais campos precisam de integridade de FK, indexação e constraints CHECK? JSON não estruturado é uma área de staging, não um schema de destino.
Quando os tipos ENUM do PostgreSQL são aceitáveis?
Conjuntos fechados que mudam raramente com cadência de release lenta. Prefira text + CHECK quando o produto adiciona valores frequentemente.
Como as views se encaixam nas boas práticas de modelagem?
Use views de compatibilidade versionadas para estabilidade da API durante migrações. Não permita que aplicativos consultem views ad-hoc em vez de tabelas de propriedade sem documentação.
O que devo levar para uma revisão de arquitetura?
ERD ou lista de tabelas, matriz de propriedade, plano de expandir-contrair para migração e uma consulta que prova que o índice do caminho crítico existe.
Relacionados
- Noções Básicas de Modelagem de Dados - exemplos introdutórios
- Modelagem Entidade-Relacionamento - referência de cardinalidade
- Limites de Schema Orientados a Domínio - limites de schema
- Estratégia de Evolução de Schema - mudança segura ao longo do tempo
- Noções Básicas de Normalização - prevenção de anomalias
Versões de Stack: Esta página foi escrita para PostgreSQL 18.4 (stable 18, maintenance 17), pgvector 0.8+, PgBouncer 1.x, Patroni 3.x, e PostGIS 3.5+.