Tabelle di eventi append-only
Registri ciò che è accaduto senza mai sovrascrivere i dati.
Tabelle di eventi append-only è una lezione SQL Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento SQL Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso SQL Academy include 4 lezioni in totale.
Che cos'è una tabella append-only
Una tabella di eventi append-only è una tabella in cui le righe vengono sempre e solo inserite, mai aggiornate o eliminate. Ogni riga rappresenta qualcosa che è accaduto in uno specifico momento.
Questo pattern è il fondamento dell'event sourcing. Invece di memorizzare lo stato attuale, si conserva ogni modifica come evento immutabile, ottenendo una cronologia completa e verificabile.
Creazione di una tabella di eventi
Una tabella di eventi ben progettata registra chi ha fatto cosa, su quale risorsa e quando. La colonna occurred_at registra il timestamp esatto e DEFAULT NOW() garantisce che venga sempre compilata automaticamente.
Notate che in questo modello non sono presenti UPDATE o DELETE: una volta scritte, le righe diventano permanenti.
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()
);Inserimento degli eventi
Ogni azione eseguita da un utente, come effettuare l'accesso, depositare denaro o modificare un indirizzo email, diventa una nuova riga. Non si torna mai indietro a modificare un evento precedente. Se è necessario correggere qualcosa, si inserisce invece un evento compensativo.
In questo modo si conserva l'intera sequenza degli eventi, nell'ordine in cui si sono verificati.
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"}');Lettura della cronologia completa
Poiché ogni modifica dello stato è memorizzata come una riga, interrogare la cronologia completa di un account richiede una semplice SELECT ordinata per tempo. È possibile ripercorrere l'intera vita di un record, dal primo evento fino a quello più recente.
SELECT
id,
event_type,
payload,
occurred_at
FROM account_events
WHERE account_id = 42
ORDER BY occurred_at ASC;Derivazione dello stato attuale
Con una tabella append-only lo stato attuale non viene memorizzato direttamente: viene derivato leggendo l'evento rilevante più recente. In questo caso, il piano attuale dell'account 42 è quello indicato dall'evento plan_upgraded o account_opened più recente.
Utilizzando ORDER BY occurred_at DESC LIMIT 1 si recupera in modo efficiente lo snapshot più 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;Applicazione dell'immutabilità con le regole
La garanzia append-only può essere applicata a livello di database utilizzando una RULE che ignora silenziosamente qualsiasi UPDATE o DELETE eseguito sulla tabella. In questo modo si impediscono modifiche accidentali da parte di qualsiasi applicazione che disponga dell'accesso in scrittura.
Un trigger che solleva un'eccezione è un'alternativa ancora più rigorosa, perché rifiuta attivamente l'operazione restituendo un errore.
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;Immutabilità tramite trigger
Un trigger che solleva un'eccezione è più rigoroso di una regola silenziosa: l'applicazione riceve immediatamente un errore se tenta di modificare un evento passato. In questo modo i bug diventano visibili invece di essere ignorati silenziosamente.
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();Conteggio degli eventi nel tempo
Le tabelle append-only rendono semplici le analisi basate sul tempo. Poiché ogni evento ha un timestamp, è possibile raggruppare i dati per giorno, settimana o mese senza colonne aggiuntive. L'esempio seguente conta quanti eventi di ogni tipo si sono verificati ogni giorno.
SELECT
DATE_TRUNC('day', occurred_at) AS day,
event_type,
COUNT(*) AS total
FROM account_events
GROUP BY 1, 2
ORDER BY 1, 2;Ricostruzione a un istante specifico
Una delle proprietà più potenti di un registro eventi è la possibilità di ricostruire lo stato di qualsiasi record così come esisteva in un momento passato. È sufficiente filtrare gli eventi fino al timestamp desiderato: non è necessaria alcuna estensione per il viaggio nel tempo.
Questa funzionalità è preziosa per il debugging, gli audit e la conformità normativa.
-- 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;Eventi compensativi invece delle correzioni
Quando si scopre un errore, ad esempio un addebito errato, non si deve eliminare l'evento non corretto. Si inserisce invece un evento compensativo che lo annulla o lo inverte. Entrambi gli eventi rimangono visibili nel registro e mostrano esattamente cosa è accaduto e quando è stata applicata la correzione.
In questo modo la traccia di audit rimane completa e a prova di manomissione.
-- 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}'
);Partizionamento di tabelle di eventi di grandi dimensioni
Le tabelle di eventi crescono rapidamente. Il partizionamento per intervalli temporali mantiene ridotte le dimensioni delle singole partizioni, velocizza le query su intervalli e consente di archiviare o eliminare le partizioni meno recenti senza intervenire sui dati recenti.
Il partizionamento dichiarativo di PostgreSQL rende tutto questo semplice: è sufficiente definire una partizione RANGE su occurred_at e lasciare che il database indirizzi automaticamente gli inserimenti.
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 delle conoscenze sulle tabelle append-only
Verificate la vostra comprensione della progettazione delle tabelle di eventi append-only.
Riepilogo: tabelle di eventi append-only
In questa lezione avete imparato a progettare e utilizzare le tabelle di eventi append-only:
- Immutabilità: le righe vengono inserite una sola volta e non vengono mai modificate. Gli eventi passati sono fatti.
- Cronologia completa: ogni modifica dello stato viene conservata, consentendo tracce di audit complete e query a un istante specifico.
- Eventi compensativi: gli errori vengono corretti aggiungendo un nuovo evento di annullamento, non eliminando quello precedente.
- Applicazione dei vincoli: regole o trigger a livello di database impediscono modifiche accidentali.
- Scalabilità: il partizionamento per intervalli mantiene efficienti i registri eventi di grandi dimensioni nel tempo.
Le tabelle append-only sono il pilastro dell'event sourcing, delle architetture CQRS e di qualsiasi sistema in cui la verificabilità e l'accuratezza storica siano fondamentali.
Domande Frequenti
La lezione «Tabelle di eventi append-only» è gratuita?
Sì — il testo completo di «Tabelle di eventi append-only» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso SQL Academy, passa a CoddyKit PRO. Il corso SQL Academy include 4 lezioni in totale.
Cosa imparerò in «Tabelle di eventi append-only»?
Registri ciò che è accaduto senza mai sovrascrivere i dati. Eserciti SQL Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare SQL Academy?
Non è richiesta alcuna esperienza precedente. SQL Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.
Quanto tempo richiede la lezione «Tabelle di eventi append-only»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione SQL Academy?
Sì. Ogni lezione SQL Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Perché conservare la cronologia
- Tabelle di eventi append-only
- Righe temporali e versionate
- Ricostruire lo stato dagli eventi