Scegliere un tipo di dato è come scegliere lo strumento giusto per un lavoro. Non useresti mica un cacciavite per piantare un chiodo (spero). Così anche nel database: il tipo di dato giusto fa davvero la differenza per le performance, il risparmio di memoria e la facilità di gestione dei dati. Per esempio, se salviamo soldi come REAL, rischiamo problemi di precisione, mentre usare TEXT invece di VARCHAR per stringhe corte fa solo sprecare memoria.
Quando scegli il tipo di dato, tieni a mente alcune cose:
Carattere dei dati
Capisci a che categoria appartengono i dati: numeri, stringhe, valori booleani, date o qualcosa di più complesso, tipo strutture JSON.
Quantità di dati
Quanti dati pensi di salvare? Per esempio, per testi fino a 50 caratteri meglio scegliere VARCHAR(50) invece di TEXT.
Precisione e range
Serve una precisione alta (tipo per i calcoli finanziari)? Vuoi limitare il range dei valori?
Frequenza e tipo di query
Quanto spesso accederai a questi dati? Occhio che tipi complessi come JSONB richiedono più risorse per essere gestiti.
Esempi di scelta dei tipi di dati
Dati diversi, esigenze diverse. A volte serve la precisione al centesimo, altre basta che ci stia tutto. Qui sotto trovi esempi di come scegliere il tipo di dato giusto per ogni situazione.
Dati finanziari
Quando si tratta di salvare soldi, come in contabilità, gli errori non sono ammessi. Quindi il tipo migliore è NUMERIC, che garantisce alta precisione. Per esempio, vogliamo una tabella con queste colonne:
| Nome colonna | Tipo di dato | Commento |
|---|---|---|
| id | SERIAL | Chiave primaria |
| amount | NUMERIC(10, 2) | Dieci cifre, di cui due dopo la virgola |
| currency_code | CHAR(3) | Codice valuta ISO, tipo "USD", "EUR" |
| transaction_date | TIMESTAMP | Data e ora della transazione, di default l'orario attuale |
Perché non REAL? Il punto è che i numeri floating point possono perdere precisione, e questo è un problema serio per i soldi.
Dati testuali
Se vuoi salvare nomi utente, indirizzi o altre stringhe, imposta sempre una lunghezza massima quando puoi. Tipo VARCHAR(50) invece di TEXT. Così eviti errori e ottimizzi la memoria.
| Nome colonna | Tipo di dato | Commento |
|---|---|---|
| id | SERIAL | Chiave primaria |
| username | VARCHAR(50) | Login utente, unico e obbligatorio |
| VARCHAR(255) | ||
| bio | TEXT | Biografia, può essere un testo lungo |
Se la lunghezza della stringa è fissa (tipo codici paese a due lettere), usa CHAR:
| Nome colonna | Tipo di dato | Commento |
|---|---|---|
| code | CHAR(2) | Codice paese ISO (tipo "US"), chiave primaria |
| name | VARCHAR(100) | Nome del paese, obbligatorio |
Dati per timestamp
Per salvare orari di eventi o calendari, di solito va bene TIMESTAMP, perché contiene sia la data che l'ora.
| Nome colonna | Tipo di dato | Commento |
|---|---|---|
| id | SERIAL | Chiave primaria |
| event_name | VARCHAR(100) | Nome dell'evento |
| start_time | TIMESTAMP | Ora di inizio evento, obbligatoria |
| end_time | TIMESTAMP | Ora di fine evento, obbligatoria |
Se ti serve solo l'orario senza la data, usa TIME, se solo la data senza orario — DATE.
Identificatori unici
Quando devi creare identificatori unici a livello globale, usa UUID. Per esempio, per generare un identificatore unico di una transazione:
| Nome colonna | Tipo di dato | Commento |
|---|---|---|
| request_id | UUID | Identificatore unico della richiesta, generato di default con gen_random_uuid() |
| endpoint | VARCHAR(255) | Indirizzo dell'API endpoint chiamato |
| timestamp | TIMESTAMP | Orario della richiesta, di default l'orario attuale |
JSONB: strutture complesse
Quando devi salvare dati con struttura variabile o complessa, tipo preferenze utente o metadati, usa JSONB.
| Nome colonna | Tipo di dato | Commento |
|---|---|---|
| user_id | SERIAL | Chiave primaria (ID utente) |
| preferences | JSONB | Preferenze utente in formato JSON |
Con JSONB è comodo lavorare, ma occhio che può rallentare se fai tante insert/update.
Array
Gli array vanno bene se devi salvare liste di dati omogenei. Tipo una lista di tag:
| Nome colonna | Tipo di dato | Commento |
|---|---|---|
| id | SERIAL | Chiave primaria |
| title | VARCHAR(255) | Titolo dell'articolo |
| tags | TEXT[] | Array di tag |
Panoramica dei tipi di dati per compito
| Tipo di compito | Tipo di dato consigliato | Esempio |
|---|---|---|
| Identificatore record | SERIAL, BIGSERIAL, UUID |
id SERIAL PRIMARY KEY |
| Quantità, numeri interi | INTEGER, BIGINT |
quantity INTEGER |
| Calcoli finanziari | NUMERIC |
price NUMERIC(10, 2) |
| Memorizzazione stringhe | VARCHAR(n), TEXT |
username VARCHAR(50) |
| Stringhe corte e fisse | CHAR(n) |
status CHAR(1) |
| Date e orari | DATE, TIME, TIMESTAMP |
created_at TIMESTAMP DEFAULT NOW() |
| Identificatori unici | UUID |
id UUID PRIMARY KEY DEFAULT gen_random_uuid() |
| Strutture complesse (JSON) | JSONB |
metadata JSONB |
| Liste di valori | ARRAY |
tags TEXT[] |
| Valore booleano | BOOLEAN |
is_active BOOLEAN |
Probabilmente conosci già tutti i tipi tranne SERIAL. Il punto è che SERIAL è praticamente un INTEGER che si usa come identificatore delle righe nelle tabelle.
Si incrementa automaticamente di 1 ogni volta che aggiungi una nuova riga. Quindi, se aggiungi 10 righe, la prima avrà id 1, la seconda 2 e così via. Di tutto questo parleremo meglio nella prossima lezione :)
GO TO FULL VERSION