In questo articolo andiamo a confrontare dal punto di vista tecnico i due modelli di gestione del dato più utilizzati in ambito enterprise: il modello relazionale, implementato sulla maggior parte dei sistemi legacy aziendali, e quello documentale, recentemente riscoperto perché in grado di superare alcune rigidità del modello relazionale.

Vediamo quindi le principali caratteristiche, le differenze di approccio a entrambi i modelli e una serie di domande utili a decidere quale modello adottare.

 

Il database relazionale

Il modello relazionale, costruito intorno al concetto di relazione, struttura i dati in modelli che sono messi in relazione tra loro tramite vincoli che si esplicitano attraverso foreign keys: per esempio la tabella figlia ha un riferimento alla tabella madre tramite il suo ID. Tale relazione è espressa con un linguaggio, solitamente un DDL (Data Definition Language).

Uno dei motivi di tanta popolarità di questo modello è il fatto che sono disponibili, anche gratuitamente, diversi tool per la gestione del database (per esempio MySQL Workbench o DBeaver per il design del database o la migrazione dello schema).

Negli esempi a seguire supporremo che il modello relazionale sia implementato su un database SQL compliant, per semplicità.

 

Il database documentale

Il modello documentale pone l’attenzione sul dato, invece che sulle relazioni. In tal senso, il dato non è visto come una tupla (o riga) all'interno di una tabella, ma come un documento con proprietà non definite a priori: non esiste un linguaggio DDL per definire uno schema e quindi in alcuni documenti qualche proprietà può mancare mentre in altri essere presente.

In questo modello le relazioni non sono rappresentate da foreign keys ma dall’annidamento dei dati: essendo destrutturato, il documento può inglobare dentro sé un altro documento o un array di documenti, andando a creare in questo modo una relazione N:1 o 1:N tra le due entità. Si va quindi a preferire l’annidamento rispetto alla esplicitazione delle relazione tramite una o più proprietà.

Negli esempi a seguire supporremo che il modello documentale sia implementato dal database MongoDB, che ultimamente ha preso piede in ambito enterprise.

 

Due diversi approcci al dato

In un approccio relazionale, l’attività di scrittura viene eseguita da un componente che scrive il dato in un unico posto ed esiste una e una sola tabella che contiene quel dato. Se si dovesse aggiungere un record, andrebbe inserita una riga a quella tabella. Al contrario se si volesse leggere quel dato, la query di lettura tipicamente dovrebbe reperire quell'informazione eseguendo la JOIN: un’operazione che permette di interrogare più tabelle, combinarne i dati e restituirli in forma filtrata.

Al contrario, un modello documentale spinge lo sviluppatore a replicare il dato in diversi posti in modo che la lettura possa essere eseguita considerando un solo data model, senza quindi costrutti simili alla JOIN.

 

Esempio: la biblioteca

Facendo un esempio semplice, possiamo pensare a come rappresentare gli autori e i libri nel modello dati di una biblioteca. Il caso d’uso è quello della ricerca per libro o per autore eseguita dagli utenti di una biblioteca tramite gli appositi terminali.

In un approccio di tipo relazionale, una possibile soluzione potrebbe essere implementata tramite l’utilizzo di due tabelle - una Autori e l’altra Libri - collegate tra loro da una proprietà della tabella Libri che mette in relazione le due tabelle in senso logico. In tale modello è anche possibile forzare il fatto che tutti i libri debbano avere un autore, e che tale autore debba essere censito nel database tramite l’utilizzo di una foreign key della tabella Libri che non ammette valore null.


Mia-Platform_Modello_Relazionale


Utilizzando invece un approccio di tipo documentale, possiamo sfruttare l’annidamento per descrivere la relazione:

  • si potrebbe creare una sola collezione Autori. Ogni autore ha un campo denominato Libri contenente un array di documenti. Ogni sottodocumento è quindi un libro. Con questa modalità, scelto un autore, si reperiscono anche tutti i suoi libri.

Mia-Platform_Modello_Documentale

  • un altro approccio potrebbe essere quello di creare una collezione Libri per cui ogni libro ha un campo Autore che contiene un documento che descrive l’autore. Con questa modalità, scelto un libro, si reperisce anche l’autore.

Mia-Platform_Modello_Documentale2

  • Un terzo modello prevede una collezione che contenga i libri come sopra descritta, una collezione che contenga gli autori come sopra descritta. In questa modalità entrambe le tipologie di lettura del dato possono essere soddisfatte senza reperire dati non necessari.

Mia-Platform_Modello_Documentale3

Scegliendo un modello documentale è possibile fare alcuni controlli di consistenza del dato, ma non altri: per esempio, utilizzando il terzo approccio, è possibile censire il libro di un autore inesistente. Infatti potrei inserire nella collezione Libri un documento il cui autore non è censito nella collezione Autori.

 

Accesso al dato in lettura

Utilizzando il modello relazionale il dato è sempre accessibile. L’accesso infatti può essere fatto da entrambe le tabelle per utilizzare entrambi i dati: partendo da Autori e tramite JOIN è possibile reperire i dati dei libri e viceversa.

 

SELECT * from Autori JOIN Libro on Autori.id = Libri.autore_id where Autore.id=??;

SELECT * from Autori JOIN Libro on Autori.id = Libri.autore_id where Libro.id=??;

 

Entrambe le letture coinvolgono entrambe le entità, per cui la modifica allo schema influisce sulle query di lettura: aggiungendo o togliendo un campo la query può tornare campi in più o in meno. Infatti se dovessimo aggiungere una colonna alla tabella Autori, entrambe le query di lettura ne verrebbero influenzate.

 

Utilizzando il modello documentale e facendo riferimento alle tre ipotesi di cui sopra, ho tre possibilità:

  • Nel primo caso, l’accesso è semplice se devo individuare un autore, ma per individuare un libro devo selezionare l’autore e mi torneranno necessariamente tutti i suoi libri;
  • Nel secondo caso, l’accesso è semplice se devo individuare un libro ma per individuare tutti i libri di un autore, devo cercare l’autore nella collezione Libri come proprietà innestata. In questo modo, però, ho una ripetizione del dato autore per ciascun libro;
  • Nel terzo modello, invece, scegliendo la collezione di partenza, posso ottenere facilmente i dati necessari senza una duplicazione di informazione.

Nel modello documentale, quindi, è molto importante scegliere il modello dati più idoneo alle attività di lettura richieste.

 

Accesso al dato in scrittura

Il modello relazionale permette di scrivere in un solo luogo il dato. In questo modo l’aggiornamento o la rimozione di una riga può essere fatta tramite un singolo comando senza l’utilizzo di JOIN: in modo automatico, tutte le nuove query di lettura erediteranno la modifica apportata al dato.

Il modello documentale, in base all'approccio utilizzato può prevedere una maggior complessità di implementazione di scrittura:

  • Nel primo approccio, l’aggiornamento dell’autore o di un libro può essere eseguito tramite una sola richiesta al database;
  • Nel secondo caso, l’aggiornamento di un libro può essere eseguito con un’unica query; anche l'aggiornamento di un autore può essere eseguito con un’unica query, ma questa deve considerare diversi documenti;
  • Infine, nel terzo caso, che prevede entrambe le collezioni, l’aggiornamento del libro o dell’autore deve essere eseguito con due query distinte (una per collezione) per garantire la consistenza del dato.

Quindi, il modello documentale potrebbe non rispettare i requisiti di atomicità e coerenza delle transazioni: la scrittura deve essere eseguita in due azioni sequenziali, violando così il principio di atomicità. Esiste, inoltre, un momento temporale, seppur breve, nel quale una collezione contiene alcuni documenti non ancora aggiornati.

 

Quale scegliere

Come sempre non esiste un silver bullet: dipende dalla tipologia di progetto e dalla criticità che c’è nell'applicativo.

Possiamo però evidenziare alcune domande che possono essere utili per scegliere quale approccio utilizzare.

 

Prevedi più letture o più scritture?

Se si pensa ad un applicativo di gestione libri, come una biblioteca, è probabile che le letture saranno eseguite più frequentemente rispetto alle scritture poiché la consultazione del catalogo è la feature principale. Infatti, le richieste di scrittura sarebbero circoscritte alle operazioni di prenotazione e/o modifica dei dati, meno frequenti rispetto alla consultazione del catalogo.
In questa tipologia di contesti, le operazioni di scrittura e di lettura hanno pesi diversi.

In un database relazionale, che comprende un numero elevato di tabelle o di records, le query di lettura potrebbero essere poco performanti se coinvolgono molte tabelle. Database con più di mille tabelle sono di difficile consultazione poiché il numero di attraversamenti su queste tabelle è ampio. Allo stesso modo, database relazionali con un numero molto alto di record (anche miliardi di righe per tabella) e con un alto numero di colonne può essere affetto dal medesimo problema prestazionale.
In questo caso, un modello documentale può essere la scelta più opportuna.

Diversamente, se il tuo progetto prevede scritture più frequenti, potrebbe essere più utile adottare un modello relazionale che, come abbiamo visto, non prevede copie del dato.

 

La sincronizzazione del dato è importante?

In un database relazionale SQL, essendo ACID, il problema non sussiste: se il dato viene aggiornato, ogni query successiva all'aggiornamento legge il dato nuovo.

In un database documentale, al contrario, se il dato viene replicato in diverse collezioni, l’aggiornamento dello stesso deve essere propagato in tutte le sue copie: è necessario tener traccia di dove viene effettuata ciascuna copia del dato.

A tal proposito sono nate soluzioni architetturali che disaccoppiano la scrittura sulla collezione principale dalla propagazione sulle copie tramite un sistema a code. Per esempio tramite l'utilizzo di un sistema a code - quale Kafka - è possibile aggiornare le varie copie in modo asincrono, senza avere un punto centrale di censimento di tutte le copie: questo facilita la gestione delle scritture delle copie.
Deve essere in ogni caso sopportato un ritardo dell'aggiornamento del dato.

 

Prevedi molte evoluzioni dello schema del database?

Durante lo sviluppo di un progetto può capitare che emerga l’esigenza di cambiare schema del dato per aggiungere, rimuovere o modificare delle proprietà. In base alla diversità dei dati presenti e alla tipologia di modifica, tale operazione può essere molto complessa.
Infatti, le modifiche dello schema possono impattare su tutte le query di lettura e scrittura. Questo comporta che, per ogni modifica, debba essere eseguita una revisione di tutte le query che coinvolgono le tabelle modificate.

Supponiamo di voler evolvere lo schema del database della biblioteca andando ad aggiungere informazioni ulteriori sull'autore, quali i premi letterari vinti o la partecipazione a concorsi.

In un modello relazionale possiamo aggiungere delle colonne alla tabella Autori o fare una o più tabelle legate all'autore.

Nel primo caso, per tenere conto di tutte le casistiche possibili, è necessario andare ad aggiungere una serie di colonne, una per ciascuna informazione. Tale implementazione permette, per ogni autore, il censimento di un solo dato per proprietà limitando quindi le capacità del modello.

Nel secondo caso, è necessario aggiungere una tabella per ogni casistica, con le relative foreign key. Per esempio possiamo andare a creare una tabella Premi, una tabella Concorsi e due tabelle ponte tra Autori e le altre due tabelle. Per ogni altra informazione che si volesse aggiungere, sarebbe necessario creare due tabelle. Il limite di questa implementazione è la manutenibilità di un elevato numero di tabelle.

Utilizzando invece un modello documentale, una possibilità potrebbe essere quella di aggiungere un campo al documento della collezione Autori, inserendo un array di documenti: in questo modo possiamo tenere traccia di tutte le informazioni richieste.
In aggiunta, attribuendo un significato logico al valore null, possiamo distinguere chi non ha ricevuto premi da coloro per cui l’informazione è sconosciuta: se il campo è un array vuoto significa che l’autore non ha premi; diversamente, se il campo è null, significa che le informazioni non sono reperibili.

Mia-Platform_Modello_Documentale4

 

L’uno non esclude l’altro: approccio primary/secondary

In architetture complesse con complessi modelli di business, gli applicativi esistenti sono spesso basati su database relazionali, le cui configurazioni si basano su requirements di business che si sono susseguiti nel tempo - nuovi prodotti, cambio di normative etc.
Tale evoluzione ha necessariamente trasformato i modelli dati sottostanti, per accogliere il nuovo volume di informazioni e organizzarle all’interno di molteplici tabelle. I modelli dati hanno saputo rispondere efficacemente alle richieste del business accrescendo la propria struttura al crescere del volume di informazioni da organizzare.

In un mondo sempre più digitalizzato, le aziende cercano di raggiungere gli utente con più canali possibili e di offrire loro informazioni aggiornate e disponibili 24/7. La proliferazione di punti di accesso ai dati e le nuove esigenze di disponibilità del dato non possono essere soddisfatte da quegli stessi sistemi, che non sono predisposti a reggere un simile carico di richieste. Per esempio, la query di lettura che prima veniva eseguita una volta al giorno, ora viene eseguita di continuo, ogni volta che l’utente accede all’app o al sito. Questo determina problemi di performance, poiché le varie proprietà richieste sono allocate su centinaia di diverse tabelle.

Questo problema è ancora più evidente quando il touchpoint richiede dati presenti su differenti database. Nonostante alcuni database engine permettano di eseguire JOIN tra database differenti, situati su host differenti, tale approccio non è consigliabile per tre ragioni:

  • Performance: come abbiamo visto eseguire la JOIN può portare inefficienze;
  • Evolutive molto difficoltose: lo schema del database è condiviso con altri applicativi su cui il team di sviluppo potrebbe non avere accesso;
  • Astrazione del modello: il database è un dettaglio implementativo della rappresentazione del modello di business che non deve essere condiviso all’esterno del team di sviluppo.

 

Per risolvere questo problema, Mia‑Platform ha sviluppato una soluzione architetturale chiamata Fast Data che prevede la creazione di un database documentale che raccoglie in modo asincrono le informazioni e le organizza per soddisfare le esigenze di tutti i touchpoint.

Mia-Platform_Fast_Data

In questo modo è possibile avere i vantaggi di entrambi i modelli: gli applicativi scrivono una sola volta il dato sui sistemi relazionali e i touchpoint interrogano il database documentale per accedere in modo sicuro e veloce ai dati opportunamente organizzati, senza appesantire i sistemi sottostanti.

 

Conclusioni

Non esiste un silver bullet: entrambi i modelli hanno dei pregi e dei difetti. Abbiamo visto che in alcuni casi conviene adottare un modello relazionale, mentre in altri contesti il modello documentale si applica meglio. Non esiste quindi un modello migliore di un altro ma solo un modello che, in determinate circostanze, calza meglio in base alla tipologia di operazione più frequente.

Se il numero delle letture supera di molto il numero delle altre operazioni, l’utilizzo di un modello documentale dovrebbe essere preso in considerazione, in modo particolare se le letture coinvolgono tante tabelle o tanti dati; al contrario un modello relazionale è consigliato quando le scritture sul database sono tante, per evitare la duplicazione del dato a ogni aggiornamento.


Articolo scritto da Tommaso Allevi, R&D Leader di Mia‑Platform

Torna all'inizio

Scarica il white paper

© MIA s.r.l. Tutti i diritti riservati