Un database è uno dei componenti fondamentali di praticamente qualsiasi sistema informatico moderno. Gestionale aziendale, sito web, applicazione mobile, piattaforma e-commerce e software interno utilizzano un database per memorizzare e recuperare informazioni in modo strutturato. Quando un utente apre la scheda di un cliente, visualizza un ordine o effettua una ricerca, dietro quella semplice operazione viene normalmente eseguita una serie di operazioni che coinvolgono applicazione, database e sistema di archiviazione.
Capire come funziona un database significa quindi andare oltre il concetto di semplice archivio. Un database moderno deve riuscire a gestire contemporaneamente migliaia di operazioni, garantire l'integrità delle informazioni, impedire accessi non autorizzati, mantenere la coerenza dei dati anche in caso di errore e restituire rapidamente le informazioni richieste dall'applicazione.
Che cos'è realmente un database
Un database è un sistema progettato per memorizzare, organizzare, interrogare e modificare dati. Nei database relazionali, le informazioni vengono generalmente organizzate attraverso tabelle composte da righe e colonne.
Una tabella clienti, per esempio, potrebbe essere strutturata così:
CREATE TABLE clienti (id INT PRIMARY KEY AUTO_INCREMENT,nome VARCHAR(100) NOT NULL,cognome VARCHAR(100) NOT NULL,email VARCHAR(255),data_creazione DATETIME);
In questo esempio id, nome, cognome, email e data_creazione rappresentano le colonne, mentre ogni cliente memorizzato rappresenta una riga.
Il database non si limita però a conservare questi valori. Deve anche sapere come identificarli, come recuperarli, come modificarli e come garantire che le operazioni effettuate dall'applicazione non compromettano la consistenza delle informazioni.
Database relazionale: tabelle e relazioni
Uno dei modelli più utilizzati in ambito aziendale è quello relazionale. Il principio fondamentale consiste nel suddividere le informazioni in più tabelle e collegarle attraverso identificativi.
Possiamo avere, ad esempio:
clienti ? ordini ? prodotti ? categorie
Un cliente può avere molti ordini, mentre ogni ordine può contenere più prodotti. Invece di inserire tutte queste informazioni nella stessa tabella, il database utilizza relazioni tra entità differenti.
Una struttura semplificata potrebbe essere:
clienti|| id_cliente?ordini|| id_ordine?righe_ordine|| id_prodotto?prodotti
Questo approccio evita duplicazioni inutili e permette di mantenere una struttura dati più coerente.
Chiavi primarie e identificazione dei record
Ogni tabella dovrebbe avere un modo affidabile per identificare univocamente le proprie righe. Nei database relazionali questo compito viene normalmente svolto dalla primary key.
Nell'esempio precedente:
id INT PRIMARY KEY AUTO_INCREMENT
significa che id identifica univocamente ogni cliente.
La chiave primaria è importante perché viene utilizzata anche per collegare tabelle differenti. Una tabella ordini potrebbe contenere:
id_ordine INT PRIMARY KEY,id_cliente INT NOT NULL
dove id_cliente rappresenta il riferimento al cliente che ha effettuato l'ordine.
Questa seconda colonna può essere definita come foreign key, creando un vincolo tra le due tabelle.
FOREIGN KEY (id_cliente)REFERENCES clienti(id)
In questo modo il database può contribuire a mantenere l'integrità della relazione tra clienti e ordini.
Come il database recupera un dato
Quando un'applicazione esegue:
SELECT *FROM clientiWHERE id = 125;
il database deve individuare il record corrispondente all'identificativo 125.
Il modo in cui viene effettuata questa ricerca dipende dalla struttura della tabella e dagli indici disponibili.
Se id è una chiave primaria, il database dispone normalmente di una struttura indicizzata che consente di individuare rapidamente il record senza dover leggere una per una tutte le righe della tabella.
Questo è uno dei motivi per cui gli indici sono fondamentali per le prestazioni dei database.
Come funzionano gli indici
Un indice può essere paragonato, concettualmente, all'indice di un libro. Senza indice potremmo essere costretti a controllare ogni pagina per trovare un determinato argomento. Con un indice possiamo individuare rapidamente la posizione nella quale cercare.
In un database il principio è simile, anche se la struttura interna è molto più complessa.
Possiamo creare un indice:
CREATE INDEX idx_clienti_emailON clienti(email);
Una query come:
SELECT *FROM clientiWHERE email = 'cliente@email.it';
può quindi beneficiare dell'indice sulla colonna email.
Gli indici, però, non sono gratuiti. Occupano spazio e devono essere aggiornati quando vengono inseriti, modificati o eliminati dati. Un database correttamente progettato deve quindi trovare un equilibrio tra velocità delle letture e costo delle operazioni di scrittura.
Cosa succede quando eseguiamo una query SQL
Quando l'applicazione invia una query SQL al database, non viene semplicemente "letta" ed eseguita riga per riga.
Il database deve analizzare la richiesta, interpretare la sintassi, valutare le condizioni e determinare quale sia il modo più efficiente per ottenere il risultato.
Una query come:
SELECT c.nome, c.cognome, o.id_ordineFROM clienti cINNER JOIN ordini oON o.id_cliente = c.idWHERE c.stato = 'ATTIVO';
richiede al database di individuare i clienti attivi, collegarli agli ordini e costruire il risultato finale.
Il motore utilizza un query optimizer per scegliere il piano di esecuzione più appropriato. La decisione può dipendere dagli indici disponibili, dalla quantità stimata di dati, dalle statistiche delle tabelle e dalla struttura della query.
Il piano di esecuzione
Per capire come il database sta realmente lavorando è possibile utilizzare strumenti come EXPLAIN.
Ad esempio:
EXPLAINSELECT *FROM clientiWHERE email = 'cliente@email.it';
Il risultato può mostrare informazioni relative al metodo di accesso, all'indice utilizzato, al numero stimato di righe analizzate e ad altri parametri utili per comprendere il comportamento dell'optimizer.
Questo diventa fondamentale quando una query SQL è lenta, perché permette di capire se il database sta utilizzando correttamente gli indici oppure se sta effettuando una scansione completa della tabella.
JOIN: come vengono collegati i dati
Le JOIN rappresentano una delle operazioni più importanti nei database relazionali.
Supponiamo di avere:
clientiidnomeordiniid_ordineid_clientetotale
Per ottenere il nome del cliente associato a ogni ordine possiamo utilizzare:
SELECTo.id_ordine,c.nome,o.totaleFROM ordini oINNER JOIN clienti cON c.id = o.id_cliente;
Il database deve quindi combinare informazioni provenienti da due tabelle sulla base della relazione tra c.id e o.id_cliente.
Quando le tabelle diventano molto grandi, la progettazione degli indici sulle colonne utilizzate nelle JOIN diventa fondamentale per mantenere buone prestazioni.
INNER JOIN, LEFT JOIN e differenze operative
Non tutte le JOIN producono lo stesso risultato.
Con INNER JOIN vengono restituite solamente le righe che hanno una corrispondenza tra le due tabelle.
Con LEFT JOIN, invece, vengono mantenute tutte le righe della tabella a sinistra anche quando non esiste una corrispondenza nella tabella collegata.
Ad esempio:
SELECTc.id,c.nome,o.id_ordineFROM clienti cLEFT JOIN ordini oON o.id_cliente = c.id;
Questa query permette di ottenere anche clienti che non hanno ancora effettuato ordini.
La scelta della JOIN non è quindi solamente una questione di sintassi SQL, ma determina direttamente quali informazioni verranno restituite dall'applicazione.
Transazioni: come il database mantiene la coerenza
Uno degli aspetti più importanti dei database aziendali è la gestione delle transazioni.
Immaginiamo un sistema bancario nel quale venga trasferito denaro da un conto a un altro. Non sarebbe accettabile completare la sottrazione dal primo conto e poi interrompere l'operazione prima di effettuare l'accredito sul secondo.
Le transazioni permettono di raggruppare più operazioni in un'unica unità logica.
Un esempio SQL può essere:
START TRANSACTION;UPDATE contiSET saldo = saldo - 100WHERE id = 1;UPDATE contiSET saldo = saldo + 100WHERE id = 2;COMMIT;
Se qualcosa va storto prima del COMMIT, è possibile utilizzare:
ROLLBACK;
per annullare le modifiche effettuate all'interno della transazione.
Questo meccanismo è fondamentale nei gestionali che eseguono più modifiche collegate tra loro.
Le proprietà ACID
Le transazioni dei database relazionali vengono generalmente associate alle proprietà ACID:
Atomicity: l'operazione viene completata integralmente oppure annullata.
Consistency: il database deve rimanere in uno stato coerente.
Isolation: le transazioni concorrenti devono essere gestite evitando interferenze indesiderate.
Durability: una volta confermata una transazione, i dati devono rimanere persistenti anche in caso di determinate interruzioni.
Queste proprietà sono particolarmente importanti nei sistemi che gestiscono ordini, pagamenti, fatturazione, disponibilità di magazzino e altre informazioni critiche.
Concorrenza: quando più utenti modificano gli stessi dati
Un database aziendale viene normalmente utilizzato contemporaneamente da molti utenti.
Immaginiamo che due operatori modifichino contemporaneamente lo stesso cliente. Il database deve gestire queste operazioni evitando che una modifica sovrascriva accidentalmente l'altra.
Entrano quindi in gioco meccanismi come locking, isolamento delle transazioni e controllo della concorrenza.
Il livello di isolamento scelto può influenzare il comportamento delle transazioni e il rapporto tra consistenza e prestazioni.
In un sistema reale la configurazione deve essere scelta in base alle operazioni eseguite dall'applicazione e non semplicemente impostata senza analisi.
Normalizzazione dei dati
Un altro concetto fondamentale nella progettazione dei database relazionali è la normalizzazione.
L'obiettivo è ridurre duplicazioni e anomalie nella gestione delle informazioni.
Supponiamo di avere una tabella nella quale il nome e l'indirizzo del cliente vengono ripetuti in ogni ordine:
Ordine 1001 | Mario Rossi | Via Roma 10Ordine 1002 | Mario Rossi | Via Roma 10Ordine 1003 | Mario Rossi | Via Roma 10
Se Mario Rossi cambia indirizzo, dovremmo modificare numerose righe.
Una progettazione relazionale più corretta potrebbe separare:
clientiordini
collegando gli ordini al cliente attraverso id_cliente.
In questo modo l'indirizzo viene memorizzato una sola volta.
La normalizzazione deve comunque essere applicata con criterio. In determinati scenari può essere necessario introdurre forme di denormalizzazione per migliorare le prestazioni di lettura.
Database relazionali e database NoSQL
Non tutti i database utilizzano tabelle relazionali.
I database NoSQL possono adottare modelli differenti, come documenti, chiave-valore, colonne o grafi.
Un database documentale può, ad esempio, memorizzare informazioni strutturate in documenti JSON-like:
{"id": 125,"nome": "Mario","cognome": "Rossi","ordini": [{"numero": 1001,"totale": 250}]}
Questo modello può essere particolarmente interessante per determinati tipi di applicazioni, ma non significa che NoSQL sia automaticamente migliore di un database relazionale.
La scelta tra MySQL, MariaDB, PostgreSQL, SQL Server, MongoDB o altri sistemi deve dipendere dalle caratteristiche dell'applicazione, dalla struttura dei dati, dalle query necessarie e dai requisiti di scalabilità.
Dove vengono realmente salvati i dati?
A livello fisico, il database deve memorizzare informazioni su dispositivi di archiviazione.
Il percorso semplificato può essere rappresentato così:
Applicazione ? Database Server ? Buffer/Cache ? Storage ? Disco/SSD.
Quando l'applicazione richiede un dato, il database può riuscire a recuperarlo dalla memoria senza dover accedere immediatamente al disco.
La cache e il buffer pool hanno quindi un ruolo importante nelle prestazioni. Nel caso di InnoDB, ad esempio, il buffer pool rappresenta una componente centrale utilizzata per memorizzare dati e indici in memoria e ridurre gli accessi allo storage. (dev.mysql.com)
Questo spiega perché le prestazioni di un database non dipendono soltanto dalla velocità dell'SSD, ma da un insieme di fattori che comprendono memoria, CPU, storage, query, indici e architettura applicativa.
Il database non è il gestionale
È importante distinguere il database dal software che lo utilizza.
Un gestionale può essere sviluppato in PHP, Python, Java, C# o altri linguaggi e utilizzare MySQL come sistema di gestione dei dati.
Il database non decide normalmente quale schermata visualizzare all'utente. Riceve richieste dal software, esegue operazioni sui dati e restituisce risultati.
Possiamo quindi avere:
Browser ? applicazione web ? backend ? database ? storage.
Quando un utente apre una scheda cliente, il browser invia una richiesta al server. Il backend interpreta la richiesta e prepara una query SQL. Il database esegue la query e restituisce i dati all'applicazione, che costruisce la risposta destinata al browser.
Capire questa catena è fondamentale per individuare correttamente i problemi di performance.
Sicurezza del database
Un database aziendale contiene spesso informazioni estremamente importanti. Per questo la sicurezza deve essere progettata su più livelli.
L'applicazione dovrebbe utilizzare un account con privilegi limitati, evitando di collegarsi al database attraverso un utente amministratore. Le credenziali devono essere protette e non inserite direttamente nel codice pubblico.
Anche la rete deve essere configurata correttamente. Un database che non deve essere raggiunto direttamente da Internet dovrebbe essere accessibile solamente dalle applicazioni o dai server autorizzati.
È inoltre importante monitorare gli accessi e mantenere procedure di backup e ripristino verificate.
Backup e ripristino
Un database senza una strategia di backup adeguata rappresenta un rischio significativo per l'azienda.
Il backup deve essere considerato come parte dell'architettura del sistema e non come una semplice copia occasionale del database.
Bisogna definire:
cosa salvare ? con quale frequenza ? dove conservare le copie ? per quanto tempo mantenerle ? come ripristinarle.
Ancora più importante è effettuare periodicamente un test di restore. Un backup che non è mai stato verificato non garantisce realmente che il database possa essere recuperato quando necessario.
Database e crescita dell'azienda
Un database progettato correttamente deve essere in grado di crescere insieme all'applicazione.
Una tabella con 10.000 record può funzionare perfettamente anche con una progettazione non ottimale. Quando raggiunge 5 o 10 milioni di record, però, gli stessi problemi possono diventare evidenti.
Per questo durante la progettazione di un database aziendale bisogna considerare anche la crescita prevista.
È necessario valutare dimensione delle tabelle, frequenza delle query, numero di utenti contemporanei, quantità di dati generati quotidianamente, spazio disponibile e strategie di archiviazione.
In sistemi particolarmente grandi possono diventare importanti tecniche più avanzate come partizionamento, replica, caching, read replica e distribuzione del carico.
Database e sviluppo software su misura
Quando viene sviluppato un software gestionale personalizzato, la progettazione del database rappresenta una delle fasi più importanti dell'intero progetto.
Una struttura dati corretta permette di sviluppare successivamente funzionalità più facilmente, mantenere le relazioni tra le informazioni e creare query efficienti.
Un database progettato male, invece, può diventare un vincolo che condiziona l'intera applicazione.
Per questo in ALLIT consideriamo database, backend e interfaccia come parti dello stesso sistema. Quando realizziamo o analizziamo un'applicazione aziendale, possiamo intervenire sulla struttura delle tabelle, sulle relazioni, sulle query SQL, sugli indici e sull'architettura complessiva per costruire una soluzione in grado di gestire correttamente i dati anche nel tempo.
Capire il database significa capire come funziona il software
Ogni volta che un gestionale mostra un cliente, registra un ordine, aggiorna un prezzo o genera un report, dietro l'interfaccia grafica vengono eseguite operazioni precise sul database.
Query, indici, transazioni, relazioni, chiavi, JOIN, cache e storage lavorano insieme per trasformare una richiesta dell'utente in un risultato.
Per questo un database non dovrebbe essere considerato semplicemente come il luogo nel quale "salvare i dati". È una componente software complessa che deve essere progettata, ottimizzata, protetta e monitorata.
Per un'azienda che utilizza applicazioni personalizzate, conoscere questa architettura significa anche comprendere perché la qualità del database può influenzare direttamente velocità del gestionale, affidabilità del sistema, sicurezza delle informazioni e possibilità di crescita futura.


