Estado ou Evento? O que seu modelo de dados está realmente armazenando?

By 6 de outubro de 2026Artigos
Dois cubos transparentes contendo dados digitais flutuantes sobre fundo escuro, representando a transferência e proteção de informações.

Existe uma diferença importante entre armazenar o estado atual de alguma coisa e armazenar os eventos que fazem esse estado mudar.

À primeira vista, parece uma escolha de modelagem simples. Se precisamos saber o valor atual, armazenamos o valor atual:

entity_id | current_value

Mas e quando precisamos responder:

  • Qual era o valor ontem?
  • Qual será o valor considerando eventos já programados?
  • Como chegamos ao estado atual?
  • O que aconteceria se um evento passado fosse corrigido?
  • Podemos reconstruir o estado em qualquer momento?
  • O valor armazenado continua consistente depois de múltiplas alterações concorrentes?

Nesse ponto, o problema deixa de ser apenas uma questão de armazenamento. Passa a ser uma questão de como o estado do sistema é representado e derivado. E o Postgres oferece ferramentas particularmente interessantes para trabalhar com esse tipo de modelo.

Estado é dado ou é consequência?

Considere uma sequência simples de eventos:

data        alteração
01/09       +10
03/09        -4
07/09        +8

Podemos armazenar diretamente:

07/09 → 14

Mas esse 14 não é um evento. Ele é uma consequência dos eventos anteriores. Isso cria duas possibilidades de modelagem.

Armazenar o estado

entity_id | current_value
----------+--------------
1         | 14

Armazenar os eventos

entity_id | event_date | quantity
----------+------------+---------
1         | 01/09      | +10
1         | 03/09      |  -4
1         | 07/09      |  +8

Armazenar apenas o estado atual simplifica as leituras, mas perde a rastreabilidade e a flexibilidade temporal.  Armazenar eventos como fonte de verdade permite reconstruir o estado em qualquer momento, lidar com eventos futuros e auditar alterações. A questão arquitetural é: Qual dessas informações é a fonte de verdade do sistema?

O problema de manter estado e histórico ao mesmo tempo

Uma aplicação pode decidir armazenar os dois:

events
current_state

Isso pode ser extremamente eficiente para leitura. Mas agora temos duas representações da mesma realidade. Sempre que um evento for inserido, alterado ou removido, o estado materializado precisa continuar correto. Imagine uma transação que:

  1. registra um novo evento;
  2. atualiza o estado atual;
  3. alguma etapa falha antes da segunda operação;
  4. ou duas transações tentam atualizar o mesmo estado simultaneamente.

Agora temos um problema de consistência. O valor atual deixou de ser apenas um dado. Ele passou a ser um dado derivado que precisa ser sincronizado.

É aqui que o banco de dados deixa de ser apenas o lugar onde armazenamos informações e passa a participar diretamente da implementação das regras do domínio.

O PostgreSQL consegue derivar esse estado

Se os eventos são a fonte de verdade, o estado pode ser calculado, uma Window Function permite transformar uma sequência de alterações em um valor acumulado:

SELECT
    event_date,
    quantity,
    SUM(quantity) OVER (
        ORDER BY event_date
    ) AS state
FROM events
ORDER BY event_date;

O resultado representa a evolução do estado:

data        alteração    estado
01/09       +10          10
03/09        -4           6
07/09        +8          14

A importância dessa consulta não está na sintaxe do SUM(). Está no fato de que o estado não precisa necessariamente existir como uma coluna armazenada, ele pode ser derivado a partir dos eventos que o determinam.

O tempo também faz parte do modelo

Agora imagine que existam eventos futuros:

01/09   +10
03/09    -4
07/09    +8
15/09    -3

A pergunta: “Qual é o estado?” fica incompleta. Precisamos perguntar: “Qual é o estado em relação a qual momento?” Esse detalhe muda a consulta. O estado em 10/09 deve considerar determinados eventos. O estado em 20/09 pode considerar outros. A dimensão temporal deixa de ser apenas um atributo dos registros e passa a fazer parte da própria regra de negócio.

Esse é um dos motivos pelos quais sistemas que trabalham com histórico, vigência ou eventos futuros podem se tornar significativamente mais complexos do que uma tabela com um simples current_value.

E se não houver um registro para determinada data?

Outro detalhe importante aparece quando queremos analisar a evolução do estado diariamente. Podemos ter eventos em:

01/09
03/09
07/09

mas querer consultar:

01/09
02/09
03/09
04/09
05/09
06/09
07/09

Não precisamos necessariamente criar registros artificiais para cada dia. O PostgreSQL consegue gerar essa dimensão temporal durante a consulta:

generate_series(
    DATE '2026-09-01',
    DATE '2026-09-07',
    INTERVAL '1 day'
)

Combinando essa série com os eventos e uma Window Function, podemos reconstruir a evolução do estado sem transformar cada ponto da linha do tempo em um registro persistido. O importante aqui não é generate_series() em si, é a possibilidade de separar a representação dos eventos da representação do tempo que queremos analisar.

Mas calcular tudo sob demanda é sempre uma boa ideia?

Não. Esse é justamente o ponto em que uma decisão técnica precisa substituir uma preferência por determinada técnica. Se temos milhões de eventos e uma aplicação consulta o estado atual milhares de vezes por segundo, recalcular todo o histórico a cada leitura provavelmente não será uma boa estratégia. Nesse cenário, podemos considerar outras abordagens:

Estado derivado sob demanda

O histórico é a fonte de verdade e o estado é calculado quando necessário.

Vantagem: consistência e capacidade de reconstrução.
Custo: processamento durante a leitura.

Estado materializado

O estado atual é armazenado e atualizado junto com os eventos.

Vantagem: leituras rápidas.
Custo: complexidade de manutenção e necessidade de garantir consistência.

Estratégia híbrida

Mantemos eventos como histórico e também algum nível de estado materializado ou agregado. Por exemplo:

eventos históricos
        ↓
checkpoint
        ↓
eventos posteriores
        ↓
estado atual

Nesse caso, não precisamos recalcular toda a história para descobrir o estado.

Essa estratégia pode ser interessante quando o volume cresce e o custo de reconstrução completa se torna relevante.

Onde o PostgreSQL entra nessa decisão?

O banco de dados não deve ser visto apenas como uma camada passiva de persistência. O Postgres oferece recursos nativos poderosos capazes de derivar estados e manipular dimensões temporais diretamente nas consultas.:

  • Window Functions para cálculos sobre sequências;
  • CTEs para organizar etapas de derivação;
  • generate_series() para trabalhar com dimensões temporais;
  • índices para reduzir o custo de acesso aos eventos;
  • particionamento para lidar com grandes volumes temporais;
  • materialized views para cenários em que resultados derivados podem ser pré-calculados;
  • transações e mecanismos de concorrência para manter alterações consistentes;
  • constraints para proteger invariantes do modelo.

A questão, portanto, não é: “Qual função do PostgreSQL resolve meu problema?” É: “Qual representação do dado torna esse problema sustentável para o meu ambiente?”

O estado atual pode ser uma projeção do histórico

Essa distinção é particularmente importante em sistemas que precisam de rastreabilidade. Se armazenamos apenas:

current_value = 14

Sabemos o resultado, mas não necessariamente sabemos como chegamos nele. Se armazenamos:

+10
-4
+8

podemos derivar:

10 → 6 → 14

E podemos fazer perguntas sobre diferentes momentos. O histórico passa a ser a fonte de verdade, enquanto o estado pode ser entendido como uma projeção desse histórico.

Isso não significa que devemos sempre adotar event sourcing, nem que armazenar estado seja uma má prática, significa apenas que essa é uma decisão que merece ser consciente.

A pergunta que vale levar para o projeto

Quando encontramos uma tabela com algo como:

current_status
current_balance
current_quantity
current_score
current_limit

vale fazer uma pergunta: Esse valor é um fato ou é uma consequência de outros dados?

Se for um fato, armazená-lo pode ser a escolha natural.
Se for uma consequência, talvez seja interessante entender:

  • Quais eventos determinam esse valor;
  • Se esses eventos são preservados;
  • Se o estado pode ser reconstruído;
  • Qual é o custo dessa reconstrução;
  • Com que frequência o estado é consultado;
  • Quais são os requisitos de consistência;
  • E se vale a pena materializar o resultado.

Essa análise é mais importante do que escolher entre uma Window Function, uma CTE ou qualquer outra funcionalidade específica.

PostgreSQL como parte da arquitetura

Derivar tudo sob demanda pode ser custoso em grandes volumes com alta concorrência. Por isso, a escolha entre armazenar o estado, derivar sob demanda ou usar estratégias híbridas (como checkpoints e vistas materializadas) deve ser uma decisão consciente baseada em requisitos de consistência, volume e padrões de acesso, e não em preferências por uma única técnica.

O PostgreSQL possui recursos suficientes para participar ativamente da construção de estados derivados, mantendo a lógica próxima dos dados quando isso fizer sentido. A decisão entre armazenar estado, derivar estado ou combinar as duas estratégias depende do domínio, do volume, do padrão de acesso e dos requisitos de consistência.

O ponto principal é reconhecer quando estamos diante de um estado que existe por si só, e quando estamos diante de um estado que é apenas o resultado de uma história.

Quando o valor atual é consequência de eventos anteriores, talvez a pergunta mais importante não seja: “Onde guardamos o valor?” Mas: “Onde está a verdade que permite reconstruí-lo?”

 

Receba mais conteúdos como este!

Assine a nossa newsletter e acompanhe conteúdos técnicos, análises e discussões sobre PostgreSQL, arquitetura e engenharia de dados.

[Quero receber os próximos conteúdos]

Share