Armazenar JSON em uma Única Célula: Solução Inteligente ou Bomba Relacional?

Introdução

Com a ascensão de APIs REST, microserviços e dados cada vez mais dinâmicos, surge uma dúvida comum entre desenvolvedores e DBAs: vale a pena armazenar dados em formato JSON dentro de uma única célula de uma tabela relacional?

A ideia parece simples e atraente: uma única coluna (geralmente do tipo TEXT, JSON ou JSONB) capaz de armazenar qualquer estrutura de dados. Mas como tudo em engenharia de software, há um preço. Neste post, vamos analisar prós, contras, e quando faz sentido (ou não) usar essa abordagem.


1. Como funciona: JSON em uma célula

Exemplo básico (MySQL):

CREATE TABLE usuarios (
  id INT PRIMARY KEY,
  dados JSON
);

INSERT INTO usuarios (id, dados) VALUES
(1, '{"nome": "Kemper", "cidade": "Rio Negrinho"}'),
(2, '{"nome": "Joana", "cidade": "Campo Alegre"}');

Consulta:

SELECT dados->>"$.nome" AS nome FROM usuarios;

PostgreSQL:

CREATE TABLE usuarios (
  id SERIAL PRIMARY KEY,
  dados JSONB
);

INSERT INTO usuarios (dados) VALUES
('{"nome": "Kemper", "idade": 30, "tecnologias": ["MikroTik", "Asterisk"]}');

SELECT dados->>'nome' AS nome FROM usuarios;

SQLite:

CREATE TABLE usuarios (
  id INTEGER PRIMARY KEY,
  dados TEXT
);

-- Sem suporte nativo a JSON, mas pode usar funções auxiliares ou tratar no app.

2. Prós

  • Flexibilidade de estrutura: você pode adicionar ou remover campos sem alterar a estrutura da tabela.
  • Boa integração com APIs: APIs REST consomem e produzem JSON.
  • Ideal para dados semiestruturados: logs, configurações, preferências.
  • Evita alterações frequentes na estrutura de tabelas.
  • PostgreSQL oferece ótimo suporte com JSONB, consultas e índices GIN.

3. Contras

  • Difícil de validar: sem constraints, qualquer coisa vira dado.
  • Índices limitados ou complexos: especialmente em MySQL e SQLite.
  • Performance: buscas dentro do JSON são mais lentas que colunas indexadas.
  • Quebra de normalização: dificulta relacionamentos e joins.
  • Dificulta relatórios e BI.
  • Complica updates parciais: mudar um campo exige parse, alteração e reescrita do JSON.

4. Quando faz sentido usar

  • Protótipos rápidos.
  • Dados com estrutura altamente variável.
  • Microserviços independentes.
  • Armazenamento de configurações:
{
  "tema": "escuro",
  "notificacoes": true,
  "idioma": "pt-BR"
}
  • Logs de atividade:
{
  "acao": "login",
  "ip": "189.XX.XX.XX",
  "timestamp": "2025-05-21T08:13:00Z"
}

5. Quando não usar

  • Relacionamentos complexos entre entidades.
  • Regras rígidas de validação e consistência.
  • Alto volume de consultas por atributos internos do JSON.
  • Necessidade de relatórios frequentes e análises estatísticas.

6. Performance e índices

PostgreSQL:

CREATE INDEX idx_json_nome ON usuarios USING GIN ((dados->>'nome'));

-- Ou indexar um campo específico do JSON:
CREATE INDEX idx_json_tecnologias ON usuarios USING GIN (dados jsonb_path_ops);

SELECT * FROM usuarios WHERE dados @> '{"nome": "Kemper"}';

MySQL:

  • A partir da versão 5.7+, permite JSON.
  • Sem suporte a índices parciais dentro do JSON.
SELECT * FROM usuarios WHERE JSON_UNQUOTE(JSON_EXTRACT(dados, '$.cidade')) = 'Campo Alegre';

7. Alternativas inteligentes

  • Normalizar onde faz sentido, e manter apenas partes imprevisíveis em JSON.
  • Usar bancos NoSQL como MongoDB se tudo for imprevisível.
  • Em PostgreSQL, usar JSONB + índices + triggers de validação.

8. Considerações finais

Armazenar dados em JSON dentro de uma célula não é errado por si só. É uma escolha de projeto que precisa ser feita com critério.

Se o seu objetivo é velocidade de prototipação, armazenamento de dados semiestruturados ou integração com APIs, pode ser uma mão na roda.

Mas se você precisa de relatórios robustos, performance em joins, integridade referencial ou consistência de dados, talvez seja melhor manter-se fiel ao bom e velho modelo relacional.

“O problema não é usar JSON. O problema é usá-lo como desculpa para ganhar tempo (mas perder depois).”

Rolar para cima