Pontos-Chave da Modelagem de Cenários de Defeitos
Um defeito de modelagem é uma lacuna entre o que um esquema realmente permite e o que o domínio realmente exige, e raramente se anuncia como um problema de esquema.
Busque em todas as páginas da documentação
Um defeito de modelagem é uma lacuna entre o que um esquema realmente permite e o que o domínio realmente exige, e raramente se anuncia como um problema de esquema.
Em vez disso, ele aparece como um número incorreto em um painel, um ticket de suporte sobre um link quebrado, um deploy que trava sob carga ou uma migração que ninguém quer tocar.
Esta página é um framework de diagnóstico: uma maneira de reconhecer a qual categoria de defeito de modelagem você está lidando antes de buscar uma correção, para que as páginas de incidentes específicas nesta seção sejam lidas como instâncias de um pequeno número de padrões recorrentes, em vez de uma lista não relacionada de bugs.
Um defeito de integridade é uma regra ausente ou incompleta que permite que o banco de dados armazene dados que o domínio considera inválidos, mais comumente uma chave estrangeira ausente que permite linhas órfãs após a exclusão de um pai.
Um defeito de cardinalidade é uma incompatibilidade entre o relacionamento que uma consulta assume e o relacionamento que o esquema realmente tem, mais comumente uma junção que silenciosamente transforma um-para-muitos em muitos-para-muitos e infla um agregado.
Um defeito temporal é uma lacuna em como o esquema representa o tempo, mais comumente armazenando timestamp without time zone para valores que precisam de um instante inequívoco.
Um defeito de evolução é o atrito introduzido por como um tipo ou restrição foi projetado para mudar ao longo do tempo, mais comumente um ENUM do PostgreSQL que requer um ALTER TYPE em nível de esquema para cada novo valor de negócio.
Essas quatro categorias não são exaustivas de todos os possíveis erros de esquema, mas cobrem a grande maioria dos defeitos que produzem incidentes reais de produção em esquemas relacionais.
Cada categoria tem uma assinatura reconhecível em como ela se manifesta, e aprender essa assinatura é o que torna o diagnóstico rápido em vez de exploratório.
A característica definidora de um defeito de modelagem é a distância do sintoma: a lacuna entre onde o defeito reside (o esquema) e onde ele se torna visível (um painel, um ticket de suporte, um deploy).
Uma chave estrangeira ausente não gera um erro quando uma linha pai é excluída, ela simplesmente deixa linhas filhas apontando para nada, e o sintoma aparece mais tarde como links quebrados ou comentários anexados a posts excluídos.
-- Detecta linhas órfãs que uma FK ausente permitiu
SELECT c.comment_id
FROM comments c
LEFT JOIN posts p ON p.post_id = c.post_id
WHERE p.post_id IS NULL;Um defeito de cardinalidade também não gera um erro, porque a consulta é executada e retorna um resultado, é simplesmente o número errado, e é por isso que a inflação por fan-out é tão frequentemente detectada por finanças ou análises que notam um total que não corresponde a uma fonte externa de verdade.
Diagnosticar um defeito começa perguntando a qual categoria a forma do sintoma corresponde, antes de perguntar qual consulta ou caminho de código o produziu.
Um total agregado incorreto aponta para um defeito de cardinalidade; um registro que não deveria existir aponta para um defeito de integridade; um valor com diferença de uma ou poucas horas aponta para um defeito temporal; um deploy bloqueado ou retardado por uma migração aponta para um defeito de evolução.
Essa primeira etapa de classificação reduz a investigação de "em algum lugar neste codebase" para uma categoria específica e bem compreendida, com causas e correções conhecidas.
Cada categoria tem uma relação diferente com a prevenção, o que importa ao decidir onde investir esforço de revisão.
Defeitos de integridade são os mais preveníveis apenas com DDL: uma restrição de chave estrangeira, uma vez adicionada, estruturalmente não pode ser violada, então a pergunta da revisão é se cada coluna com formato *_id que referencia outra tabela realmente possui uma.
Defeitos de cardinalidade são mais difíceis de prevenir estruturalmente, porque o esquema pode estar perfeitamente correto enquanto uma consulta específica ainda assume o relacionamento errado; a prevenção aqui se inclina mais para a revisão de consultas e a saída do EXPLAIN do que para restrições.
Defeitos temporais são em grande parte preveníveis por uma única regra permanente (armazene timestamptz, converta no momento da exibição), que é barata de impor na revisão, mas cara de adaptar depois que uma tabela já tem anos de dados ambíguos de hora local.
Defeitos de evolução são preveníveis escolhendo uma representação inicial que espera mudar, como text com uma restrição CHECK em vez de ENUM, trocando uma pequena quantidade de força de validação pela capacidade de adicionar valores sem uma alteração de esquema bloqueadora.
| Categoria | Sintoma Típico | Causa Raiz | Correção Estrutural |
|---|---|---|---|
| Integridade | Linhas órfãs, links quebrados, estados impossíveis | Chave estrangeira ou restrição ausente ou incompleta | Adicionar REFERENCES com uma ação explícita ON DELETE |
| Cardinalidade | Agregados inflados, linhas duplicadas nos resultados | Consulta assume 1:N onde o relacionamento real é M:N | Agregar antes de juntar, ou modelar a junção explicitamente |
| Temporal | Valores com diferença de horas, picos de suporte na estação DST | timestamp without time zone armazenando tempo local ambíguo | Armazenar timestamptz, converter para hora local apenas na exibição |
| Evolução | Deploys bloqueados ou retardados por uma migração | ENUM ou tipo rígido que requer alteração em nível de esquema por novo valor | text + CHECK, ou uma estratégia de enum expandir-contrair |
Transformar um incidente diagnosticado em uma correção duradoura geralmente significa duas ações separadas: corrigir a instância específica e adicionar uma verificação (uma regra de lint, uma etapa de revisão de migração, uma consulta CI) que capture a mesma categoria antes que ela chegue à produção novamente.
Tratar cada incidente como uma correção única sem essa segunda etapa é como a mesma categoria de defeito continua reaparecendo sob um nome de tabela diferente.
timestamp without time zone é ambíguo durante essas transições, independentemente de quantos fusos horários a base de usuários abrange.ENUM é bom para conjuntos verdadeiramente fixos e raramente mutáveis, mas uma coluna de status que ganha novos valores à medida que o negócio evolui transforma cada adição em um evento de migração em nível de esquema.Uma lacuna entre o que um esquema realmente permite e o que o domínio realmente exige, que se manifesta como um sintoma em vez de um erro direto.
É a causa subjacente por trás da maioria dos cenários de incidentes documentados nesta seção.
A maioria deles produz resultados que são tecnicamente saídas SQL válidas, apenas factualmente incorretas ou incompletas, em vez de acionar uma violação de restrição.
É isso que torna a "distância do sintoma" a ideia diagnóstica chave nesta página.
Combine a forma do sintoma com uma categoria: um total agregado incorreto aponta para cardinalidade, um registro impossível ou órfão aponta para integridade, um valor com diferença de horas aponta para temporal, e um deploy bloqueado aponta para evolução.
Cada categoria tem uma correção estrutural diferente, e tratar o sintoma visível sem identificar a categoria tende a deixar o esquema livre para produzir o mesmo defeito em outro lugar.
A classificação transforma uma investigação ampla em uma direcionada.
Sim - uma FK ausente é um dos defeitos mais preveníveis, porque a correção é uma única restrição, mas ainda assim é comum porque a ausência de uma restrição não produz nenhum erro imediato para pegá-la.
Um esquema pode estar perfeitamente correto enquanto uma consulta específica ainda assume o relacionamento errado entre tabelas, então nenhuma restrição sozinha pode preveni-lo.
A prevenção depende mais da revisão de consultas e da leitura da saída do EXPLAIN do que do DDL.
Ele armazena um valor sem um offset registrado, o que faz com que o mesmo valor armazenado represente diferentes instantes reais dependendo da interpretação.
Essa ambiguidade é exatamente o tipo de lacuna domínio-versus-esquema que esta página define como um defeito de modelagem.
Adicionar um novo valor a um ENUM do PostgreSQL é um evento DDL (ALTER TYPE ... ADD VALUE) que pode bloquear brevemente operações dependentes, o que transforma uma mudança de negócio rotineira (um novo valor de status) em uma migração de esquema sensível ao deploy.
Adicione uma verificação, como uma regra de lint, uma etapa de revisão de migração ou uma consulta CI recorrente, que capture a mesma categoria de defeito antes que ela chegue à produção novamente.
Corrigir apenas a instância específica deixa a categoria livre para reaparecer em outro lugar.
Sim - um bug de junção fan-out (cardinalidade) às vezes é descoberto porque também dependia de dados que deveriam ter sido rejeitados por uma restrição ausente (integridade).
Diagnosticar a categoria principal primeiro ainda ajuda a dimensionar a investigação, mesmo quando uma segunda categoria está envolvida.
Não - esta página fornece as categorias e a abordagem diagnóstica, enquanto as outras páginas documentam instâncias específicas e concretas (chaves estrangeiras ausentes, junções fan-out, bugs de timestamp, migrações de enum) em detalhes completos.
Leia esta página primeiro para saber a qual página específica recorrer.
Versões de Stack: Esta página é conceitual e não está vinculada a uma versão específica de stack, embora o comportamento de migração
ENUMdescrito se aplique ao PostgreSQL 18.4 (estável 18, manutenção 17).
Revisado por Chris St. John·Última atualização: 15 de jul. de 2026