Decisão: escolha o tipo de dado certo
Escolher um tipo de dado é uma das decisões mais caras de corrigir depois: o tipo errado produz resultados errados (ex.: float para dinheiro), desperdício de espaço e consultas lentas. Esta árvore orienta você para o tipo certo para campos numéricos, de texto, de data/hora, de chave (PK), semiestruturados (JSON) e de categoria (ENUM), e destaca armadilhas clássicas como dinheiro e character sets.
Que tipo de dado você está armazenando?
O tipo certo é determinado pela natureza do dado. Em qual categoria o campo se enquadra: um número, texto, uma data/hora, a chave primária da tabela, dados flexíveis/semiestruturados (JSON) ou um conjunto limitado de categorias?
- Valor numérico (quantidade, dinheiro, medida, contador)
- Texto (nome, descrição, código)
- Data e/ou hora
- Estou projetando uma chave primária (PK)
- Campos flexíveis/aninhados/variáveis (dados semiestruturados)
- Um conjunto limitado e conhecido de categorias (status, tipo, prioridade)
O número é inteiro ou decimal — e é dinheiro?
Para numéricos, a distinção mais crítica é a exatidão. O valor é inteiro (quantidade, ID, contador) ou decimal? Se for decimal, é DINHEIRO/um valor financeiro? Ponto flutuante binário (FLOAT/DOUBLE) nunca é usado para dinheiro nem onde se exige exatidão, porque produz erros de arredondamento.
- Inteiro (quantidade, contador, id)
- Dinheiro ou decimal exato (preço, saldo, taxa)
Recomendação: inteiro (SMALLINT / INT / BIGINT)
Para inteiros, escolha o menor tipo que cubra o intervalo necessário. Um tipo desnecessariamente grande desperdiça espaço e tamanho de índice; mas, para campos que podem crescer, como contadores/PKs, largura suficiente é essencial para evitar overflow.
Recomendação: NUMERIC / DECIMAL — NUNCA FLOAT para dinheiro
Para dinheiro e decimais exatos, use NUMERIC/DECIMAL de ponto fixo (exato). FLOAT/DOUBLE são ponto flutuante binário e não conseguem armazenar valores como 0.1 com exatidão; somas/multiplicações produzem desvios de centavos, saldos errados e problemas de auditoria.
Recomendação: texto — VARCHAR vs TEXT vs CHAR
Para texto, usa-se VARCHAR/TEXT para comprimento variável e CHAR para comprimento realmente fixo. Nos engines modernos, a diferença de armazenamento entre VARCHAR e TEXT é em geral desprezível; a decisão real é se deve haver um limite semântico (uma restrição de comprimento).
Recomendação: data/hora — TIMESTAMP com fuso horário
Se você armazena um instante (o horário de um evento), escolha um tipo que considere o fuso horário. Armazenar sem fuso horário leva a cálculos e comparações errados entre regiões/mudanças de horário de verão.
Recomendação: chave primária — BIGINT vs UUID
Há duas opções principais para uma PK: um número crescente (BIGINT identity/sequence) ou um UUID. Uma PK numérica é pequena e amigável ao índice, mas previsível e exige geração centralizada; um UUID pode ser gerado de forma distribuída, mas é maior e sua ordem aleatória pode prejudicar o índice.
Recomendação: JSON / JSONB — use com moderação
O tipo JSON é poderoso para campos com schema flexível, aninhados ou esparsos; mas a disciplina relacional (constraints, índices, segurança de tipos) pode se perder. Regra: mova os campos fixos e consultados com frequência para colunas normais e mantenha no JSON apenas a parte realmente variável.
Recomendação: ENUM vs tabela de lookup (referência)
Há duas opções para conjuntos limitados de categorias: o tipo ENUM do engine, ou uma tabela de lookup + foreign key. O ENUM é compacto e simples, mas adicionar um valor exige uma alteração de schema; uma tabela de lookup é flexível e pode carregar atributos extras (descrição, flag de ativo, ordem).