0Pricing
SQL Academy · Aula

Tabelas de Eventos Somente para Acréscimo

Registre o que aconteceu, sem nunca sobrescrever.

Tabelas de Eventos Somente para Acréscimo é uma aula grátis de SQL Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de SQL Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de SQL Academy inclui 4 aulas no total.

O que é uma tabela somente para inserção?

Uma tabela de eventos somente para inserção é uma tabela na qual as linhas só são inseridas — nunca atualizadas ou excluídas. Cada linha representa algo que aconteceu em um momento específico.

Esse padrão é a base da origem de eventos. Em vez de armazenar o estado atual, você armazena cada alteração como um evento imutável, obtendo um histórico completo e auditável.

Criando uma tabela de eventos

Uma tabela de eventos bem projetada registra quem fez o quê, em qual recurso e quando. A coluna occurred_at registra o carimbo de data e hora exato, e DEFAULT NOW() garante que ele seja sempre preenchido automaticamente.

Observe que não há UPDATE nem DELETE neste projeto — as linhas se tornam permanentes assim que são gravadas.

CREATE TABLE account_events (
  id           BIGSERIAL PRIMARY KEY,
  account_id   BIGINT      NOT NULL,
  event_type   TEXT        NOT NULL,
  payload      JSONB,
  occurred_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

Inserindo eventos

Cada ação de um usuário — entrar na conta, depositar dinheiro, alterar um e-mail — se torna uma nova linha. Você nunca volta para editar um evento anterior. Se algo precisar ser corrigido, você insere um evento compensatório.

Isso preserva a sequência completa do que aconteceu, na ordem em que aconteceu.

INSERT INTO account_events (account_id, event_type, payload)
VALUES
  (42, 'account_opened',  '{"plan": "free"}'),
  (42, 'email_verified',  '{"email": "alice@example.com"}'),
  (42, 'plan_upgraded',   '{"from": "free", "to": "pro"}');

Lendo o histórico completo

Como cada alteração de estado é armazenada como uma linha, consultar o histórico completo de uma conta é uma simples operação SELECT ordenada por tempo. Você pode reproduzir toda a trajetória de um registro, desde o primeiro evento até o mais recente.

SELECT
  id,
  event_type,
  payload,
  occurred_at
FROM account_events
WHERE account_id = 42
ORDER BY occurred_at ASC;

Derivando o estado atual

Em uma tabela somente para inserção, você não armazena diretamente o estado atual — você o deriva lendo o evento relevante mais recente. Aqui, o plano atual da conta 42 é aquele indicado pelo evento plan_upgraded ou account_opened mais recente.

Usar ORDER BY occurred_at DESC LIMIT 1 busca com eficiência o instantâneo mais recente.

SELECT payload->>'to'  AS current_plan
FROM   account_events
WHERE  account_id = 42
  AND  event_type IN ('account_opened', 'plan_upgraded')
ORDER BY occurred_at DESC
LIMIT 1;

Impondo a imutabilidade com regras

A garantia de somente inserção pode ser imposta no nível do banco de dados usando uma RULE que ignora silenciosamente qualquer UPDATE ou DELETE na tabela. Isso impede alterações acidentais de qualquer aplicação que tenha acesso de gravação.

Um gatilho que gera uma exceção é uma alternativa ainda mais rigorosa, pois rejeita ativamente a operação com um erro.

CREATE RULE no_update_events AS
  ON UPDATE TO account_events
  DO INSTEAD NOTHING;

CREATE RULE no_delete_events AS
  ON DELETE TO account_events
  DO INSTEAD NOTHING;

Imutabilidade por meio de um gatilho

Um gatilho que gera uma exceção é mais rigoroso do que uma regra silenciosa — a aplicação recebe um erro imediatamente se tentar alterar um evento passado. Assim, os erros ficam visíveis em vez de serem ignorados silenciosamente.

CREATE OR REPLACE FUNCTION deny_event_mutation()
RETURNS TRIGGER AS $$
BEGIN
  RAISE EXCEPTION 'Event table is append-only: % is not allowed', TG_OP;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_deny_event_mutation
BEFORE UPDATE OR DELETE ON account_events
FOR EACH ROW EXECUTE FUNCTION deny_event_mutation();

Contando eventos ao longo do tempo

Tabelas somente para inserção tornam simples as análises baseadas em tempo. Como cada evento tem um carimbo de data e hora, você pode agrupá-los por dia, semana ou mês sem nenhuma coluna adicional. O exemplo abaixo conta quantos eventos de cada tipo ocorreram por dia.

SELECT
  DATE_TRUNC('day', occurred_at) AS day,
  event_type,
  COUNT(*)                        AS total
FROM account_events
GROUP BY 1, 2
ORDER BY 1, 2;

Reconstrução em um momento específico

Uma das propriedades mais poderosas de um registro de eventos é a capacidade de reconstruir o estado de qualquer registro como ele existia em um momento passado. Basta filtrar os eventos até o carimbo de data e hora desejado — não é necessária nenhuma extensão de viagem no tempo.

Isso é extremamente útil para depuração, auditorias e conformidade regulatória.

-- What plan was account 42 on at the end of last month?
SELECT payload->>'to' AS plan_at_snapshot
FROM   account_events
WHERE  account_id = 42
  AND  event_type IN ('account_opened', 'plan_upgraded')
  AND  occurred_at <= DATE_TRUNC('month', NOW()) - INTERVAL '1 second'
ORDER BY occurred_at DESC
LIMIT 1;

Eventos compensatórios em vez de correções

Quando um erro é descoberto — por exemplo, uma cobrança incorreta — você não exclui o evento incorreto. Em vez disso, insere um evento compensatório que o cancela ou reverte. Ambos os eventos continuam visíveis no registro, mostrando exatamente o que aconteceu e quando a correção foi feita.

Isso mantém a trilha de auditoria completa e evidencia qualquer adulteração.

-- A charge was applied by mistake; record a reversal
INSERT INTO account_events (account_id, event_type, payload)
VALUES (
  42,
  'charge_reversed',
  '{"reason": "billing_error", "reverses_event_id": 17}'
);

Particionando tabelas de eventos grandes

As tabelas de eventos crescem rapidamente. O particionamento por intervalo de tempo mantém as partições individuais pequenas, acelera as consultas por intervalo e permite arquivar ou remover partições antigas sem afetar os dados recentes.

O particionamento declarativo do PostgreSQL torna isso simples: defina uma partição RANGE em occurred_at e deixe o banco de dados direcionar as inserções automaticamente.

CREATE TABLE account_events_2025
  PARTITION OF account_events
  FOR VALUES FROM ('2025-01-01') TO ('2026-01-01');

CREATE TABLE account_events_2026
  PARTITION OF account_events
  FOR VALUES FROM ('2026-01-01') TO ('2027-01-01');

Verificação de conhecimentos sobre tabelas somente para inserção

Teste sua compreensão sobre o projeto de tabelas de eventos somente para inserção.

Recapitulação: tabelas de eventos somente para inserção

Nesta lição, você aprendeu a projetar e usar tabelas de eventos somente para inserção:

  • Imutabilidade — as linhas são inseridas uma vez e nunca modificadas. Os eventos passados são fatos.
  • Histórico completo — cada alteração de estado é preservada, permitindo trilhas de auditoria completas e consultas referentes a um momento específico.
  • Eventos compensatórios — os erros são corrigidos adicionando um novo evento de reversão, não excluindo o antigo.
  • Imposição — regras ou gatilhos no nível do banco de dados impedem alterações acidentais.
  • Escalabilidade — o particionamento por intervalo mantém o desempenho de grandes registros de eventos ao longo do tempo.

As tabelas somente para inserção são a base da origem de eventos, das arquiteturas CQRS e de qualquer sistema em que a auditabilidade e a precisão histórica sejam essenciais.

Perguntas Frequentes

A aula “Tabelas de Eventos Somente para Acréscimo” é grátis?

Sim — o texto completo de “Tabelas de Eventos Somente para Acréscimo” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de SQL Academy, atualize para CoddyKit PRO. O curso de SQL Academy inclui 4 aulas no total.

O que vou aprender em “Tabelas de Eventos Somente para Acréscimo”?

Registre o que aconteceu, sem nunca sobrescrever. Você pratica SQL Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar SQL Academy?

Nenhuma experiência prévia é necessária. SQL Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Tabelas de Eventos Somente para Acréscimo”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de SQL Academy?

Sim. Cada aula de SQL Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Por Que Manter o Histórico
  2. Tabelas de Eventos Somente para Acréscimo
  3. Linhas Temporais e Versionadas
  4. Reconstruindo o Estado a Partir de Eventos
← Voltar para SQL Academy