I database non relazionali

// obiettivi di apprendimento
Comprendere i limiti del modello relazionale nel contesto Big Data e i motivi dell’emergere dei database NoSQL
Distinguere le proprietà ACID (RDBMS) dalle proprietà BASE (NoSQL) e capirne il trade-off
Riconoscere le quattro categorie NoSQL (Document, Key-Value, Column-family, Graph) con esempi e casi d’uso
Scegliere consapevolmente tra SQL e NoSQL in base ai requisiti di un’applicazione reale
🎬
Video
Lezione video completa su NoSQL e categorie
Guarda →
📄
Slides
Slide riassuntive ACID vs BASE e categorie NoSQL
Scarica →
🧪
Lab
Esercizi comparativi SQL → documento JSON
GitHub →
🔗
Risorse
Link a documentazione MongoDB, Redis, Neo4j
Vedi →

Perché il modello relazionale non basta più?

I database relazionali sono nati negli anni ’70 per gestire dati strutturati, transazioni bancarie, sistemi ERP. Per decenni hanno dominato. Ma con l’avvento del Web 2.0, dei social network e dell’IoT, sono emerse esigenze radicalmente nuove: miliardi di record, dati semi-strutturati o privi di schema fisso, scalabilità su decine di server, scritture continue a ritmo elevatissimo.

Il modello relazionale mostra i suoi limiti in questi scenari:

  • Schema rigido: ogni modifica alla struttura (ALTER TABLE) è costosa e rischiosa su tabelle da miliardi di righe
  • JOIN costosi: su dataset enormi le operazioni di join diventano proibitive in termini di CPU e I/O
  • Scalabilità verticale: un RDBMS scala bene aumentando la potenza di un singolo server, ma ha un tetto fisico; scalare orizzontalmente (più macchine) è complesso e spesso non supportato nativamente
  • Impedance mismatch: i dati nel codice (oggetti, JSON, array annidati) hanno una forma diversa da quella tabulare → serve una traduzione costante (ORM)
// contesto storico

Il termine NoSQL compare ufficialmente nel 2009 in un meetup a San Francisco organizzato da Johan Oskarsson per discutere di database non relazionali distribuiti. Non significa “contro SQL”, ma “Not Only SQL“: esistono scenari in cui il modello relazionale non è la scelta ottimale.

ACID vs BASE: due filosofie a confronto

I RDBMS tradizionali garantiscono le proprietà ACID, che assicurano la correttezza assoluta dei dati in ogni circostanza. I sistemi NoSQL spesso adottano un modello più rilassato chiamato BASE, che sacrifica la consistenza immediata in favore della disponibilità e della scalabilità.

ACID — RDBMS
A — Atomicità
La transazione è tutto o niente. Se un’operazione fallisce, si fa rollback completo.
C — Consistenza
Il DB passa da uno stato valido a un altro stato valido. I vincoli non vengono mai violati.
I — Isolamento
Le transazioni concorrenti non si interferiscono. Il risultato è come se fossero eseguite in serie.
D — Durabilità
Dopo il commit, i dati persistono anche in caso di crash (write-ahead log).
BASE — NoSQL
BA — Basically Available
Il sistema risponde sempre alle richieste, anche se i dati potrebbero non essere aggiornati.
S — Soft State
Lo stato del sistema può cambiare nel tempo anche senza input (propagazione aggiornamenti).
E — Eventually Consistent
Con il tempo, tutti i nodi del cluster convergeranno allo stesso valore. Non è immediato.
// esempio concreto

Su Facebook, se aggiorni il tuo stato, un tuo amico in un altro continente potrebbe vedere la versione precedente per qualche secondo. Questo è “eventually consistent“: i dati alla fine saranno coerenti, ma non istantaneamente. Per un social network è accettabile. Per un bonifico bancario no.

Il teorema CAP

// definizione formale

Il teorema CAP (Brewer, 2000) afferma che un sistema distribuito può garantire al massimo due delle tre proprietà: Consistency (tutti i nodi vedono gli stessi dati), Availability (ogni richiesta riceve una risposta), Partition Tolerance (il sistema funziona anche se la rete si divide).

Poiché le partizioni di rete in un sistema distribuito sono inevitabili, la scelta reale è tra CP (consistenza + tolleranza partizionamento) e AP (disponibilità + tolleranza partizionamento).

  • RDBMS tradizionali (CA): MySQL, PostgreSQL — ottimi su un singolo nodo, ma scalabilità orizzontale complessa
  • CP: MongoDB (write concern majority), HBase, Zookeeper — consistenza prioritaria
  • AP: CouchDB, Cassandra, DynamoDB — disponibilità prioritaria, eventual consistency

Le quattro categorie NoSQL

1. Document Store

📄 Document Store — MongoDB, CouchDB, Firestore

Ogni record è un documento (JSON/BSON) con struttura libera. I documenti sono raggruppati in collezioni (equivalenti delle tabelle). Non esiste schema fisso: ogni documento può avere campi diversi.

{
  "_id": "ObjectId('64a1f2...')",
  "nome": "Mario Rossi",
  "email": "mario@example.com",
  "indirizzo": {
    "via": "Via Roma 1",
    "citta": "Milano"
  },
  "ordini": [
    { "id": 101, "prodotto": "Laptop", "prezzo": 999 },
    { "id": 102, "prodotto": "Mouse", "prezzo": 29 }
  ]
}

⟶ Un cliente con i suoi ordini in un unico documento: niente JOIN, lettura in O(1).

Embedding vs Referencing: in MongoDB puoi includere dati correlati direttamente nel documento (embedding) oppure usare riferimenti a ID di altri documenti (referencing). L’embedding è ottimo per dati strettamente correlati e acceduti insieme; il referencing è preferibile quando i dati sono condivisi tra molti documenti.

AspettoSQL (tabella ORDINI)MongoDB (documento)
StrutturaRighe con colonne fisseDocumento JSON annidato
RelazioniJOIN su chiave esternaEmbedding o $lookup
SchemaFisso (ALTER TABLE)Flessibile (schema-less)
Uso tipicoSistemi transazionaliCMS, e-commerce, profili utente

2. Key-Value Store

🔑 Key-Value Store — Redis, DynamoDB, Memcached

Il modello più semplice: ogni dato è identificato da una chiave univoca e associato a un valore (stringa, numero, lista, hash, set). Redis mantiene tutto in memoria RAM, garantendo letture e scritture in O(1).

# Redis CLI — esempi base
SET sessione:user42 ‘{“nome”:”Mario”,”ruolo”:”admin”}’ EX 3600
GET sessione:user42
INCR contatore:visite
LPUSH coda:email “mario@example.com”

Casi d’uso tipici di Redis:

  • Cache applicativa: risultati di query SQL costose memorizzati in Redis → risposta in microsecondi invece di millisecondi
  • Sessioni utente: dati di login con TTL automatico (EX = expire after N secondi)
  • Contatori in tempo reale: like, visite, messaggi non letti
  • Code di lavori (job queue): produttore inserisce task, consumatore li estrae con LPOP/BRPOP
  • Pub/Sub: notifiche real-time tra microservizi

3. Column-Family Store

📊 Column-Family Store — Apache Cassandra, HBase, ScyllaDB

I dati sono organizzati per colonne anziché per righe. Ogni riga ha una chiave e può avere un numero arbitrario di famiglie di colonne. Ottimizzato per scritture massive e query su singole colonne di dataset enormi (petabyte).

Cassandra usa un modello masterless (nessun single point of failure): tutti i nodi sono equivalenti, i dati sono distribuiti con consistent hashing. Scrittura su commit log + memtable → flush su SSTable (immutabili). Ideale per: log di eventi IoT, metriche di sistema, feed di attività social (es. timeline Twitter).

4. Database a Grafo

🕸️ Graph Database — Neo4j, Amazon Neptune, ArangoDB

I dati sono modellati come nodi (entità) e archi (relazioni), entrambi con proprietà. Le relazioni sono “first-class citizens”: non si calcolano con JOIN, ma sono fisicamente memorizzate come puntatori.

// Cypher (linguaggio Neo4j): trova gli amici degli amici di Mario
MATCH (mario:Persona {nome: “Mario”})
      -[:CONOSCE]->(amico)-[:CONOSCE]->(amico_di_amico)
RETURN amico_di_amico.nome

Con SQL equivalente: tre JOIN annidati, esponenzialmente più lenti su grafi profondi.

Casi d’uso tipici:

  • Social network: “persone che potresti conoscere” (amici degli amici)
  • Fraud detection: rilevare pattern anomali tra transazioni e account
  • Knowledge graph: Wikipedia, Google Knowledge Graph
  • Motori di raccomandazione: Netflix, Amazon (“chi ha visto X ha visto anche Y”)

Riepilogo: quando scegliere SQL vs NoSQL?

CriterioScegli SQLScegli NoSQL
Schema dei datiFisso, strutturato, relazionaleFlessibile, variabile, semi-strutturato
ConsistenzaCritica (transazioni finanziarie)Eventual consistency accettabile
ScalabilitàVerticale (scale-up)Orizzontale (scale-out, sharding)
Tipo di queryQuery complesse con JOIN multipliAccesso per chiave, aggregazioni massive
Volume datiDa KB a decine di GBDa GB a petabyte
Velocità scritturaModerata (overhead ACID)Molto alta (nessun lock globale)
Esempi applicativiERP, banca, e-commerce tradizionaleSocial media, IoT, analytics, gaming
// nella pratica

Molte architetture moderne usano entrambi: PostgreSQL per i dati transazionali (ordini, pagamenti), Redis come cache e per le sessioni, MongoDB per i cataloghi prodotti, Elasticsearch per la ricerca full-text. Si chiama Polyglot Persistence: usare il DB giusto per ogni tipo di dato.

📌 Riepilogo — Punti chiave
  • I DB NoSQL nascono per rispondere ai limiti del modello relazionale: schema rigido, difficoltà di scalabilità orizzontale, join costosi su big data
  • ACID garantisce correttezza assoluta (usato da RDBMS); BASE sacrifica la consistenza immediata per guadagnare disponibilità e scalabilità (usato da NoSQL)
  • Il teorema CAP dimostra che un sistema distribuito può garantire al massimo due tra Consistency, Availability e Partition Tolerance
  • Quattro categorie NoSQL: Document store (MongoDB), Key-Value (Redis), Column-family (Cassandra), Graph (Neo4j)
  • La scelta SQL vs NoSQL dipende dal tipo di dato, dalla consistenza richiesta, dal volume e dal pattern di accesso
  • In produzione si usa spesso polyglot persistence: più DB specializzati per esigenze diverse nella stessa applicazione

Lascia un commento