Salta al contenuto principale

Glossario

ACID

ACID è l'insieme di garanzie offerte da una transazione relazionale: Atomicità, Consistenza, Isolamento e Durabilità. L'atomicità rende la transazione tutto-o-niente; la consistenza porta il database da uno stato valido a un altro rispettando tutti i vincoli; l'isolamento impedisce alle transazioni concorrenti di interferire; la durabilità conserva i dati committati anche dopo i crash. Queste proprietà sono il fondamento della correttezza nei database SQL come PostgreSQL, MySQL/InnoDB e Oracle.

Funzione di aggregazione

Una funzione di aggregazione calcola un singolo valore su un insieme di righe, come COUNT, SUM, AVG, MIN e MAX. Gli aggregati sono di solito abbinati a GROUP BY per ridurre gruppi di righe a una riga per gruppo. Le righe possono essere filtrate prima dell'aggregazione con WHERE e dopo l'aggregazione con HAVING.

Indice B-tree

Un B-tree è la struttura di indice predefinita nella maggior parte dei database relazionali e mantiene le chiavi ordinate in un albero bilanciato, così ricerche, scansioni di intervallo e recupero ordinato avvengono in tempo logaritmico. Accelera i predicati di uguaglianza e di intervallo (=, <, >, BETWEEN) e le query con ORDER BY sulle colonne indicizzate. Non aiuta le ricerche LIKE '%x' con wildcard iniziale.

Teorema CAP

Il teorema CAP afferma che un archivio dati distribuito può garantire al massimo due tra Consistenza, Disponibilità e Tolleranza alle partizioni contemporaneamente. Poiché in pratica le partizioni di rete sono inevitabili, un sistema distribuito sceglie di fatto tra consistenza e disponibilità quando si verifica una partizione. Inquadra i compromessi degli store SQL e NoSQL distribuiti.

Cardinalità

La cardinalità descrive il numero di valori distinti in una colonna o il numero di righe che una query o una join è prevista produrre. Le colonne ad alta cardinalità (come una chiave primaria) sono molto selettive e si indicizzano bene; quelle a bassa cardinalità (come un flag booleano) sono pessimi candidati a indice da sole. Il pianificatore usa le stime di cardinalità per scegliere l'ordine di join e i metodi di accesso.

Vincolo CHECK

Un vincolo CHECK limita i valori ammessi in una colonna o riga a quelli che soddisfano un'espressione booleana, per esempio CHECK (price >= 0). Il database lo applica a ogni insert e update, rifiutando le righe che lo violano. Porta le regole di dominio nello schema così i dati non validi non possono essere persistiti.

Indice clustered

Un indice clustered determina l'ordine fisico di archiviazione delle righe della tabella, quindi i dati della tabella sono memorizzati nelle pagine foglia dell'indice. Una tabella può avere un solo indice clustered. In SQL Server e MySQL/InnoDB la chiave primaria è per default l'indice clustered; PostgreSQL non ha un indice clustered permanente, solo il comando una tantum CLUSTER.

Colonna

Una colonna è un attributo denominato e tipizzato di una tabella che contiene un valore per riga. Ogni colonna ha un tipo di dato (come INTEGER, TEXT, TIMESTAMP), un default opzionale e vincoli opzionali come NOT NULL. L'insieme delle colonne definisce la forma di ogni riga della tabella.

Common Table Expression (CTE)

Una Common Table Expression è un insieme di risultati temporaneo e denominato definito con WITH che esiste per la durata di una singola istruzione. Le CTE migliorano la leggibilità nominando i passaggi intermedi e abilitano la ricorsione con WITH RECURSIVE per i dati gerarchici. Una CTE referenziata una sola volta è logicamente equivalente a una tabella derivata ma più leggibile.

Indice composito

Un indice composito (multi-colonna) copre più di una colonna in un ordine definito, per esempio (customer_id, created_at). Serve le query che filtrano su un prefisso sinistro delle colonne, quindi l'ordine conta: un indice su (a, b) aiuta WHERE a = ? e WHERE a = ? AND b = ? ma non WHERE b = ? da sola. Scegliere l'ordine giusto è una delle decisioni di tuning a maggior impatto.

Connection pool

Un connection pool mantiene un insieme limitato di connessioni aperte al database che i thread dell'applicazione prendono in prestito e restituiscono, evitando il costo di aprire una nuova connessione TCP e un nuovo handshake di autenticazione per ogni query. La dimensione del pool va calibrata: troppo piccola affama il throughput, troppo grande sovraccarica il database di sessioni concorrenti. HikariCP e pgbouncer sono implementazioni comuni.

Vincolo

Un vincolo è una regola che il database impone sui dati di una tabella, inclusi PRIMARY KEY, FOREIGN KEY, UNIQUE, NOT NULL e CHECK. I vincoli proteggono l'integrità dei dati a livello di archiviazione così i bug applicativi non possono persistere uno stato non valido. Il database rifiuta qualsiasi istruzione che violerebbe un vincolo e annulla la transazione colpevole.

Cursore

Un cursore è un oggetto del database che permette a un client di iterare sulle righe di un risultato una alla volta o a lotti, invece di materializzare l'intero insieme in memoria. I cursori lato server sono utili per lo streaming di grandi risultati, mentre l'iterazione lato client è comune nei driver applicativi. Tenere cursori aperti dentro transazioni lunghe può bloccare risorse e va evitato.

Deadlock

Un deadlock si verifica quando due o più transazioni detengono ciascuna un lock di cui l'altra ha bisogno, così nessuna può procedere. I database rilevano i deadlock e li risolvono annullando una transazione (la vittima), che l'applicazione deve riprovare. Acquisire i lock in un ordine coerente tra le transazioni è il modo standard per ridurre la frequenza dei deadlock.

Denormalizzazione

La denormalizzazione introduce deliberatamente ridondanza (come colonne duplicate o aggregati precalcolati) in uno schema normalizzato per accelerare le letture al costo di scritture più complesse. Scambia le garanzie di integrità della normalizzazione con le prestazioni delle query e si applica tipicamente ai percorsi di reportistica a forte lettura. I dati ridondanti devono essere mantenuti coerenti, spesso tramite trigger, viste materializzate o logica applicativa.

DDL (Data Definition Language)

La DDL è il sottoinsieme di SQL che definisce e modifica la struttura del database, inclusi CREATE, ALTER, DROP e TRUNCATE. Le istruzioni DDL operano su oggetti di schema come tabelle, indici e viste piuttosto che sui dati delle righe. In molti database la DDL è transazionale in PostgreSQL ma causa un commit implicito in MySQL e Oracle.

DML (Data Manipulation Language)

La DML è il sottoinsieme di SQL che legge e modifica i dati delle righe: SELECT, INSERT, UPDATE, DELETE e MERGE. Le istruzioni DML vengono eseguite all'interno delle transazioni e possono essere annullate. Sono le operazioni quotidiane che un'applicazione invia ai dati.

Chiave esterna

Una chiave esterna è una colonna o un insieme di colonne che fa riferimento alla chiave primaria (o a una chiave univoca) di un'altra tabella, imponendo l'integrità referenziale. Il database impedisce di inserire una riga figlia che punta a un padre inesistente e può propagare o limitare cancellazioni e aggiornamenti. Le chiavi esterne documentano le relazioni e le mantengono coerenti a livello di archiviazione.

Dipendenza funzionale

Una dipendenza funzionale esiste quando un insieme di colonne determina univocamente un altro, scritto A -> B, cioè ogni valore di A è associato a esattamente un valore di B. Le dipendenze funzionali sono la base formale della normalizzazione: le forme normali sono definite in base a quali dipendenze sono ammesse. Identificarle correttamente guida un design pulito dello schema.

GROUP BY

GROUP BY suddivide le righe in gruppi che condividono gli stessi valori nelle colonne elencate così le funzioni di aggregazione calcolano un risultato per gruppo. Ogni colonna non aggregata nella lista SELECT deve comparire nella clausola GROUP BY (secondo lo standard SQL). Viene eseguita dopo il filtraggio WHERE e prima di HAVING e della proiezione SELECT.

HAVING

HAVING filtra i gruppi prodotti da GROUP BY usando condizioni su valori aggregati, per esempio HAVING COUNT(*) > 5. Differisce da WHERE, che filtra le singole righe prima del raggruppamento. Poiché viene eseguito dopo l'aggregazione, HAVING può riferirsi a funzioni di aggregazione che WHERE non può.

Indice

Un indice è una struttura dati ausiliaria che accelera la ricerca delle righe al costo di spazio aggiuntivo e scritture più lente, poiché l'indice deve essere mantenuto a ogni modifica. I tipi comuni includono B-tree (ricerche ordinate e intervalli), hash (solo uguaglianza), GIN/GiST (full-text, array, geometria in PostgreSQL) e bitmap. Il pianificatore decide se usare un indice è più economico di una scansione sequenziale.

Livello di isolamento

Un livello di isolamento definisce quanto sono visibili tra loro gli effetti delle transazioni concorrenti, scambiando consistenza con concorrenza. Lo standard SQL definisce Read Uncommitted, Read Committed, Repeatable Read e Serializable, che progressivamente vietano letture sporche, letture non ripetibili e letture fantasma. La maggior parte dei database usa per default Read Committed; Serializable offre la garanzia più forte al costo di contesa più alta.

JOIN

Una join combina righe di due o più tabelle in base a una colonna correlata, producendo un unico insieme di risultati. INNER JOIN restituisce solo le righe corrispondenti; LEFT/RIGHT OUTER JOIN mantiene le righe non corrispondenti di un lato con NULL; FULL OUTER JOIN mantiene quelle non corrispondenti di entrambi; CROSS JOIN produce il prodotto cartesiano. La condizione di join (di solito in ON) determina quali righe si accoppiano.

Vista materializzata

Una vista materializzata memorizza fisicamente il risultato precalcolato di una query, a differenza di una vista normale che viene ricalcolata a ogni riferimento. Accelera aggregazioni e join costose al costo dell'obsolescenza, poiché deve essere aggiornata (manualmente o su schedule). PostgreSQL supporta REFRESH MATERIALIZED VIEW CONCURRENTLY per non bloccare i lettori durante il refresh.

MVCC (Multi-Version Concurrency Control)

L'MVCC consente a lettori e scrittori di procedere senza bloccarsi a vicenda mantenendo più versioni di una riga e mostrando a ogni transazione uno snapshot consistente. PostgreSQL e Oracle usano l'MVCC così una SELECT non attende mai un UPDATE della stessa riga. Il costo è la necessità di ripulire le versioni di riga obsolete, gestita dal vacuum in PostgreSQL.

Normalizzazione

La normalizzazione è il processo di strutturazione di uno schema relazionale per ridurre la ridondanza ed evitare anomalie di aggiornamento, inserimento e cancellazione, scomponendo le tabelle in base alle dipendenze funzionali. Le forme normali comuni sono 1NF, 2NF, 3NF e BCNF, ciascuna elimina una classe specifica di anomalia. Uno schema ben normalizzato memorizza ogni fatto una sola volta, semplificando le scritture.

NULL

NULL rappresenta l'assenza di un valore, non lo zero né una stringa vuota, e segue la logica a tre valori in cui i confronti con NULL danno UNKNOWN. Per questo column = NULL non è mai vero; bisogna usare IS NULL o IS NOT NULL. Le funzioni di aggregazione come COUNT(column) saltano i NULL, mentre COUNT(*) conta tutte le righe.

OLAP

OLAP (Online Analytical Processing) descrive carichi di lavoro che scansionano e aggregano grandi volumi di dati storici per reportistica e analisi, privilegiando il throughput di lettura rispetto alla latenza transazionale. I sistemi OLAP usano spesso storage colonnare, schemi a stella e modelli fact/dimension denormalizzati. Si contrappongono all'OLTP, che gestisce molte piccole transazioni concorrenti.

OLTP

OLTP (Online Transaction Processing) descrive carichi di molte transazioni di lettura/scrittura brevi e concorrenti, come l'elaborazione di ordini o il banking, dove contano soprattutto bassa latenza e correttezza ACID. Gli schemi OLTP sono tipicamente normalizzati e fortemente indicizzati per le ricerche puntuali. Si contrappongono ai carichi analitici OLAP.

ORM (Object-Relational Mapping)

Un ORM mappa le tabelle relazionali a oggetti in un linguaggio applicativo, generando SQL per le operazioni comuni così gli sviluppatori lavorano con entità invece che con query grezze. ORM come Hibernate, Prisma e SQLAlchemy accelerano lo sviluppo CRUD ma possono nascondere problemi di prestazioni come il pattern delle query N+1. Conoscere l'SQL che l'ORM genera è essenziale per usarlo bene.

Partizionamento

Il partizionamento divide una tabella logica in più pezzi fisici (partizioni) per intervallo, lista o hash su una chiave di partizione, così query e manutenzione toccano solo le partizioni rilevanti. Migliora la gestibilità (eliminare un'intera partizione è veloce) e può migliorare le prestazioni tramite il pruning delle partizioni. È distinto dallo sharding, che distribuisce le partizioni su server separati.

Prepared statement

Una prepared statement è un modello SQL analizzato e pianificato una sola volta, poi eseguito molte volte con parametri diversi vincolati. Migliora le prestazioni riusando il piano e, soprattutto, previene la SQL injection perché i valori dei parametri non vengono mai concatenati nel testo SQL. I driver la espongono tramite segnaposto come ? o $1.

Chiave primaria

Una chiave primaria è la colonna o l'insieme di colonne che identifica univocamente ogni riga di una tabella e non può essere NULL. Una tabella ha al massimo una chiave primaria, che il database impone con un indice univoco. È l'ancora che le chiavi esterne referenziano per esprimere le relazioni.

Ottimizzatore di query

L'ottimizzatore di query è il componente del database che sceglie un piano di esecuzione per un'istruzione SQL, stimando il costo di ordini di join, metodi di accesso e algoritmi alternativi tramite le statistiche delle tabelle. Poiché l'SQL è dichiarativo, due query equivalenti possono produrre piani molto diversi. Leggere l'output di EXPLAIN e mantenere fresche le statistiche è il modo di collaborare con l'ottimizzatore.

Integrità referenziale

L'integrità referenziale è la garanzia che ogni valore di chiave esterna faccia riferimento a una riga esistente nella tabella referenziata, così non ci sono riferimenti pendenti. Il database la impone rifiutando le operazioni che orfanizzerebbero le righe o propagandole secondo l'azione referenziale della chiave esterna. Mantiene coerenti le relazioni tra le tabelle.

Replica

La replica copia i dati da un database primario a una o più repliche, offrendo scalabilità in lettura, alta disponibilità e disaster recovery. La replica sincrona attende la conferma delle repliche prima del commit (durabilità più forte, latenza più alta); la replica asincrona no (latenza più bassa, possibile perdita di dati in caso di failover). Le read replica possono servire il traffico di reportistica per alleggerire il primario.

Riga

Una riga (o tupla) è un singolo record in una tabella, che contiene un valore per ogni colonna. Le righe sono l'unità di dato che le istruzioni DML inseriscono, aggiornano e cancellano. Nel pensiero SQL orientato agli insiemi, una tabella è un insieme non ordinato di righe e le query operano su interi insiemi alla volta.

Savepoint

Un savepoint segna un punto all'interno di una transazione al quale si può tornare senza annullare l'intera transazione, con SAVEPOINT nome e ROLLBACK TO SAVEPOINT nome. Abilita il rollback parziale di un'operazione multi-step mantenendo il lavoro precedente. È utile per la logica di retry e per isolare sotto-operazioni rischiose.

Schema

Uno schema è la definizione formale della struttura di un database, inclusi tabelle, colonne, tipi, vincoli, indici e viste. In PostgreSQL e altri, lo schema è anche un namespace che raggruppa gli oggetti all'interno di un database. Una migrazione modifica lo schema in modo controllato e versionato.

Sequenza

Una sequenza è un oggetto del database che genera una serie di numeri monotonicamente crescente, usata comunemente per popolare le chiavi primarie surrogate. È indipendente da qualsiasi tabella e garantisce l'unicità anche in concorrenza. PostgreSQL la espone tramite nextval()/currval() e le colonne SERIAL/IDENTITY sono zucchero sintattico sopra le sequenze.

Sharding

Lo sharding partiziona orizzontalmente i dati su più server di database indipendenti (shard) tramite una chiave di shard, così ogni shard contiene un sottoinsieme delle righe. Scala scritture e archiviazione oltre una singola macchina ma aggiunge complessità: le join e le transazioni cross-shard sono difficili e la scelta della chiave di shard è critica. Differisce dalla replica, che copia gli stessi dati.

SQL injection

La SQL injection è una vulnerabilità in cui input controllato dall'attaccante viene concatenato in un'istruzione SQL, permettendo all'attaccante di alterarne il significato per leggere, modificare o distruggere dati. Si previene usando istruzioni parametrizzate (prepared) così l'input viene sempre trattato come dato, mai come codice. Rimane una delle vulnerabilità web più comuni e pericolose.

Stored procedure

Una stored procedure è un blocco denominato e precompilato di SQL e logica procedurale memorizzato nel database e invocato per nome. Può incapsulare operazioni multi-istruzione complesse vicino ai dati, riducendo i round trip, ma sposta la logica di business nel database dove è più difficile testarla e versionarla. Usala per operazioni data-intensive, non come generico livello applicativo.

Chiave surrogata

Una chiave surrogata è un identificatore artificiale generato dal sistema (come un intero auto-incrementale o un UUID) usato come chiave primaria al posto di un valore di business naturale. È stabile, compatta e non deve mai cambiare quando cambiano gli attributi di business, il che mantiene semplici le chiavi esterne. Il compromesso è una colonna in più senza significato di business.

Transazione

Una transazione è un'unità di lavoro eseguita come una singola operazione atomica, delimitata da BEGIN e COMMIT (o ROLLBACK). Fornisce le garanzie ACID così il lavoro parziale non è mai visibile e un fallimento lascia il database invariato. Raggruppare istruzioni correlate in un'unica transazione è il modo per mantenere coerenti le operazioni multi-step.

Trigger

Un trigger è codice procedurale che il database esegue automaticamente in risposta a un INSERT, UPDATE o DELETE su una tabella, prima o dopo l'evento. I trigger si usano per l'audit, la manutenzione di colonne derivate e l'imposizione di regole complesse. Vengono eseguiti implicitamente, il che rende facile trascurare gli effetti collaterali, quindi vanno usati con parsimonia e documentati chiaramente.

Vincolo UNIQUE

Un vincolo UNIQUE garantisce che nessuna coppia di righe condivida lo stesso valore nelle colonne vincolate, ammettendo uno o più NULL a seconda del database. È imposto con un indice univoco. A differenza di una chiave primaria, una tabella può avere più vincoli univoci e possono ammettere NULL.

Vista

Una vista è una query memorizzata e denominata che si comporta come una tabella virtuale, calcolata a ogni riferimento. Incapsula join e filtri complessi dietro un nome semplice, supporta il controllo accessi esponendo una proiezione ristretta e disaccoppia i consumatori dallo schema sottostante. A differenza di una vista materializzata, una vista semplice non memorizza dati e riflette sempre le tabelle di base correnti.

Funzione finestra

Una funzione finestra calcola un valore su un insieme di righe correlate alla riga corrente (la finestra) senza ridurle a una singola riga di output, tramite la clausola OVER (...). Funzioni come ROW_NUMBER(), RANK(), LAG(), LEAD() e SUM() progressivo abilitano classifiche, totali progressivi e confronti periodo su periodo. A differenza degli aggregati con GROUP BY, le funzioni finestra mantengono ogni riga di input.

Write-Ahead Log (WAL)

Un write-ahead log registra ogni modifica prima che venga applicata ai file dati, così il database può recuperare uno stato coerente dopo un crash riapplicando o annullando le modifiche registrate. È alla base della durabilità (la D di ACID) ed è il fondamento del recupero point-in-time e della replica fisica. PostgreSQL lo chiama WAL; altri sistemi lo chiamano redo log o transaction log.