Modelagem decide a performance antes do primeiro índice
Todo problema de performance em banco relacional começa antes da consulta lenta: começa no formato das tabelas. Um índice novo se resolve em uma tarde. Trocar a chave primária de uma tabela grande em produção, não. Por isso modelagem é decisão de negócio: ela define quanto custa crescer, quanto custa mudar de regra e quanto custa manter o sistema rodando.
PostgreSQL e MySQL resolvem o mesmo problema por caminhos diferentes, e ignorar isso no desenho do schema cobra caro depois. No InnoDB, a chave primária é o índice clusterizado: os dados ficam organizados por ela e todo índice secundário carrega essa chave internamente. Uma chave primária grande ou aleatória infla todos os índices da tabela, não apenas um. No PostgreSQL a tabela é um heap e a chave primária é um índice separado, o que dá mais liberdade, mas exige saber que a ordem física dos dados não acompanha a chave sem manutenção explícita.
Tipos, chaves e constraints: onde o modelo vaza para o custo
Decisões de tipo parecem detalhe e não são:
- Valores monetários em
numeric, nunca em ponto flutuante. Arredondamento no banco vira divergência contábil no fechamento. - Datas com fuso em
timestamptzno PostgreSQL e convenção explícita de UTC no MySQL. Fuso implícito é relatório errado esperando acontecer. - Chave estrangeira com o mesmo tipo e a mesma collation da chave referenciada. Tipo divergente impede uso de índice na junção e transforma consulta simples em varredura completa.
uuidcomo chave primária apenas quando houver necessidade real, como geração no cliente ou distribuição entre nós. No InnoDB, uuid aleatório fragmenta a inserção e aumenta o tamanho de todos os índices secundários.not null,checkeuniquenão são burocracia: impedem que dado inválido chegue ao relatório e evitam tratamento defensivo espalhado pelo código de aplicação.
Considere uma distribuidora que guardou o endereço de entrega como texto livre no pedido. A operação funcionou por um bom tempo. Quando a diretoria pediu relatório de frete por região, o dado não existia de forma consultável: o time passou a extrair cidade por expressão regular em toda a base, e a correção exigiu nova estrutura, migração em lotes e convivência entre os dois formatos por um período. O custo não veio da consulta, veio do modelo.
Normalizar, desnormalizar e o lugar do JSON
Terceira forma normal continua sendo o padrão sadio para dados transacionais: uma verdade em um lugar só, atualização barata e menos inconsistência. Desnormalizar faz sentido quando a leitura domina e a duplicação é controlada por um único ponto de escrita, como um total consolidado mantido por gatilho ou por rotina da aplicação.
JSON no PostgreSQL (jsonb) e no MySQL é útil para atributos esparsos e payloads de origem externa que não participam de junção nem de constraint. Vira dívida quando campos que precisam de validação, relatório e índice passam a morar dentro do documento. A regra prática: se o campo aparece em filtro recorrente, em regra de negócio ou em obrigação fiscal, ele merece coluna própria.
Na prática
Para quem mantém software em produção, modelagem aparece em decisões pequenas e frequentes:
- Antes de criar índice, verifique se o problema é consulta ou desenho. Índice sobre coluna mal tipada resolve pouco.
- Trate migração de schema como mudança de produto: script versionado, ensaio em base com volume realista, janela definida e plano de reversão.
- Padronize convenções de nomes, tipos de chave, fuso e collation, e registre isso em um documento curto. Consistência reduz erro e acelera revisão de código.
- Revise o modelo a cada nova entidade relevante, porque é ali que o custo futuro é decidido, não no meio do incidente.